Search code examples
javascripthtmlangulartypescriptvalidation

Custom Validation for required on selectionChange


I have a dropdown and two text-boxes in Angular HTML. I would like to implement a functionality where, if the 'payable_frequency' dropdown is selected, then either of the 'payable_commission' fields(min or max) becomes required and able to display a mat-error message. Otherwise, both payable_commission fields are not required. I attempted to use (selectionChange)="customFunction($event.value)" and min_payable_commission:['',[customValidatorFunction]], but neither approach worked. Kindly provide a solution to this issue. I prefer not to directly use [Validator.required] in the .ts file or the "required" keyword in the .html file.

ngOnInit(): void {
  this.couauiChargesForm = this.formBuilder.group({
      id: [''],
      payable_frequency_ref_id:[''],
      min_payable_commission:[''],
      max_payable_commission:[''],
    });
}
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12">
    <mat-label>Payable Frequency</mat-label>
    <mat-form-field class="example-full-width" appearance="outline">
        <mat-select formControlName="payable_frequency_ref_id">
            <mat-option value="" >Select Payable Frequency</mat-option>
            <mat-option [value]="data.id" *ngFor="let data of billingFrequencyData">{{ data.master_key }}</mat-option>
        </mat-select>
    </mat-form-field>                            
</div>

<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12">
    <div class="form-group">
        <mat-label>Min Payable Commission</mat-label>
        <mat-form-field class="example-full-width" appearance="outline">
            <input matInput formControlName="min_payable_commission" type="number" placeholder="0">
            <mat-error *ngIf="couauiChargesForm.get('min_payable_commission')">This Field is required!</mat-error>
        </mat-form-field>
    </div>
</div>

<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12">
    <div class="form-group">
        <mat-label>Max Payable Commission</mat-label>
        <mat-form-field class="example-full-width" appearance="outline">
            <input matInput formControlName="max_payable_commission" type="number" min="0" placeholder="0">
            <mat-error *ngIf="couauiChargesForm.get('max_payable_commission')">This Field is required!</mat-error>
        </mat-form-field>
    </div>
</div>


Solution

  • There are a couple of ways to do this.

    The method I prefer is to define a custom validator function that checks the value of payable_frequency_ref_id and just returns null if is not set. https://angular.io/guide/form-validation#defining-custom-validators.

    So, something like this:

    // I'm not familiar with the Form Builder, so I wrote it out.    
    public couauiChargesForm: FormGroup = new FormGroup({
      id: new FormControl(''),
      min_payable_commission: new FormControl('', this.commissionValidator),
      max_payable_commission: new FormControl('', this.commissionValidator)
    });
    
    private commissionValidator(control: FormControl) {
      const refId = this.couauiChargesForm.controls.payable_frequency_ref_id.value;
      
      if (refId) {
        if (!control.value) {
          return {required: 'this field is required'};
        }
      }
      return null;
    }

    Another method is to programmatically add and remove validators from your min and max controls, when reacting to form control value changes. You have to subscribe to payable_frequency_ref_id's valueChange event (remember to unsubscribe in onDestroy!), then you can add and remove validators from your other controls. Then call each control's UpdateValueAndValidity() method. Not my preferred approach however.