Home > Software design >  How to make reactive form fields mandatory based on condition at html code in Angular 11
How to make reactive form fields mandatory based on condition at html code in Angular 11

Time:01-08

I have two select/dropdown fields in my form and second dropdown field renders based on a condition *ngIf="selectedStdntList?.packages". But in below code, it stops submit form even if the condition *ngIf="selectedStdntList?.packages" is not true and second dropdown is not rendered on the screen.

student-list.component.html

<form [formGroup]="moveStudentForm" #formDirective="ngForm" (ngSubmit)="moveStudent();">
    <uitk-form-field>
      <label uitkLabel>Student List:</label>
      <uitk-select id="my-required-reactive-select" formControlName="stdntListCtrl"
        [itemList]="stdntListDropdown" [showError]="moveStudentForm?.controls?.stdntListCtrl?.errors?.required"
        defaultLabel="Please Select" defaultLabelFlag="true">
      </uitk-select>
      <uitk-form-field-error
        *ngIf="moveStudentForm?.controls?.stdntListCtrl?.errors?.required && moveStudentForm?.controls?.stdntListCtrl?.touched">
        <span>Please select student list</span>
      </uitk-form-field-error>
    </uitk-form-field>


    <uitk-form-field *ngIf="selectedStdntList?.packages">
      <label uitkLabel>Package:</label>
      <uitk-select id="my-required-reactive-select" formControlName="moveStudentPackageCtrl" [itemList]="packagesDropdown"
        [showError]="moveStudentForm?.controls?.packageCtrl?.errors?.required" defaultLabel="Please Select"
        defaultLabelFlag="true">
      </uitk-select>
      <uitk-form-field-error
        *ngIf="moveStudentForm?.controls?.packageCtrl?.errors?.required && moveStudentForm?.controls?.packageCtrl?.touched">
        <span>Please select package</span>
      </uitk-form-field-error>
    </uitk-form-field>
</form>

student-list.component.ts

    @Component({
        selector: 'stdnt-list',
        templateUrl: './stdnt-list.component.html',
        styleUrls: ['./stdnt-list.component.scss']
    })
    export class StdntListComponent implements OnInit {
        
        stdntListDropdown: IUITKSelectItemProps[] = [];
        moveStudentForm: FormGroup;
    
        constructor(private dataService: DataService)
            
            this.moveStudentForm = new FormGroup({
                stdntListCtrl: new FormControl(null, Validators.required),
                moveStudentPackageCtrl: new FormControl(null, Validators.required),
            });
        }
    
        ngOnInit() {
            this.stdntList = this.dataService.loadStudentData();
        }
        
        moveStudent() {
            ...
        }
    }

Desired output:

If second field condition *ngIf="selectedStdntList?.packages" is true then only validator of this field should work, else only first field validator should work and form should be allowed to be submitted.

CodePudding user response:

You can dynamically set validator based on the selectedStdntList value.

    this.moveStudentForm = new FormGroup({
      stdntListCtrl: new FormControl(null, Validators.required),
      moveStudentPackageCtrl: new FormControl(null)
    });
    
    // Need to add/clear validator based on selectedStdntList?.packages value dynamically
    // Not sure how are you using 'selectedStdntList' in StdntListComponent
    // Below code should be executed whenever 'selectedStdntList' value changes
    
    const moveStudentPackageCtrl = this.moveStudentForm.get('moveStudentPackageCtrl');
    if (this.selectedStdntList?.packages) {
      // set validators - PS: this will clear previous Validators if any, and only set the ones specified here
      moveStudentPackageCtrl?.setValidators(Validators.required);
    } else {
      // clear validator
      moveStudentPackageCtrl?.clearValidators();
    }
    moveStudentPackageCtrl?.updateValueAndValidity();

As an alternative instead of setting and clearing validators, you can even add or remove form control moveStudentPackageCtrl dynamically:

    this.moveStudentForm = new FormGroup({
      stdntListCtrl: new FormControl(null, Validators.required)
    });
    
    
    // Add/remove control based on selectedStdntList?.packages value dynamically
    // Not sure how are you using 'selectedStdntList' in StdntListComponent
    // Below code should be executed whenever 'selectedStdntList' value changes
    
    if (this.selectedStdntList?.packages) {
      this.moveStudentForm.addControl('moveStudentPackageCtrl', new FormControl(null, Validators.required));
    } else {
      this.moveStudentForm.removeControl('moveStudentPackageCtrl');
    }

CodePudding user response:

to make a formControl "not validate" you has two options: create a custom validator or disabled the FormControl

Create a custom validator type "requiredIf". Create a custom validator has the problem that you need UpdateValueAndValiddity the FormControl when the condition change. In this SO it's use the event (change) of a mat-input. I don't know if your "uitk-select" has an event (change) or similar (*)

To disable the formControl in an normal input you can not use [disabled], else you need use a directive (like this another SO), or, again, if your "uitk-select" has an [disable] property or you can use the event (change) to disabled the formControl -using the methods enable and disabled-. but in this case important you need use

[style.display]="!selectedStdntList?.packages?'none':null"

not *ngIf

(*)When you use a non standar library, indicate the library you use help us to help you.

  •  Tags:  
  • Related