1

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.

James Z
  • 12,209
  • 10
  • 24
  • 44
Shailesh Vikram Singh
  • 1,433
  • 17
  • 26

2 Answers2

2

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');
    }
Siddhant
  • 2,911
  • 2
  • 8
  • 14
  • It is important to note here that calling `setValidators()` method without calling `updateValueAndValidity()` method will amount to no changes in the form. That is, no changes will be effected on the form and its validations. `updateValueAndValidity()` is actually the method that informs Angular to effect the new changes made to the form control. Hence, always make sure it is called after calling `setValidators()` on controls. Check it here https://www.codementor.io/@jimohhadi/angular-validators-with-conditional-validation-in-reactive-forms-pj5z7gsq5 – Andrei Manolache May 15 '23 at 16:14
0

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.

Eliseo
  • 50,109
  • 4
  • 29
  • 67