How to add required validation to matInput if the checkbox is checked

Viewed 377

I have 5 checkboxes in a FormGroup, display using ngFor, and 1 matInput that has to be a required field if any of the checkboxes is checked.

.ts

this.gridForm = this.fb.group({
      cbox1: [''],
      cbox2: [''],
      cbox3: [''],
      cbox4: [''],
      cbox5: [''],
      input1: ['', Validators.required] });

.html

            <div *ngFor="let table of xTables; let i = index;">
              <mat-checkbox formControlName="{{xTableKeys[i]}}">{{table}}</mat-checkbox>
            </div>
            <mat-form-field>
              <input matInput formControlName="xType" placeholder="X Type">
            </mat-form-field>

I've added required validators for the input, but what I need is to make it required only after any of the checkboxes is checked. Current status is I cannot submit the form unless I fill in the input, but with or without checking the checkbox.

2 Answers

You can use custom validator:


    this.gridForm = this.fb.group({
          cbox1: [''],
          cbox2: [''],
          cbox3: [''],
          cbox4: [''],
          cbox5: [''],
          input1: ['', [requiredIfValidator(() => this.gridForm.get('cbox1' && 'cbox2' && 'cbox3' && 'cbox4' && 'cbox5').value)]] 
    });
    
        function requiredIfValidator(predicate) {
          return (formControl => {
            if (!formControl.parent) {
              return null;
            }
            if (formControl.parent.get('cbox1').value) {
              return Validators.required(formControl);
            }
            if (formControl.parent.get('cbox2').value) {
              return Validators.required(formControl);
            }
            if (formControl.parent.get('cbox3').value) {
              return Validators.required(formControl);
            }
            if (formControl.parent.get('cbox4').value) {
              return Validators.required(formControl);
            }
            if (formControl.parent.get('cbox5').value) {
              return Validators.required(formControl);
            }
            return null;
          })
        };

Subscribe to the value changes to trigger the conditional validation when you toggle the checkbox.


    this.gridForm.get('cbox1').valueChanges
      .subscribe(value => {
        this.gridForm.get('input1').updateValueAndValidity();
      });
    this.gridForm.get('cbox2').valueChanges
      .subscribe(value => {
        this.gridForm.get('input1').updateValueAndValidity();
      });
    this.gridForm.get('cbox3').valueChanges
      .subscribe(value => {
        this.gridForm.get('input1').updateValueAndValidity();
      });
    this.gridForm.get('cbox4').valueChanges
      .subscribe(value => {
        this.gridForm.get('input1').updateValueAndValidity();
      });
    this.gridForm.get('cbox5').valueChanges
      .subscribe(value => {
        this.gridForm.get('input1').updateValueAndValidity();
      });

This is known as custom conditional field validator. Checkout this link https://medium.com/ngx/3-ways-to-implement-conditional-validation-of-reactive-forms-c59ed6fc3325

enableInput should also be an array. Otherwise it will take the value of the last updated checkbox only.

<div *ngFor="let table of xTables; let i = index;">
    <mat-checkbox formControlName="{{xTableKeys[i]}}" [checked]="enableInput[i]" 
    (change)="enableInput[i] = !enableInput[i]">{{table}}</mat-checkbox>
</div>
<mat-form-field>
    <input matInput formControlName="xType" placeholder="X Type" 
    [attr.disabled]="getInputState()">
</mat-form-field>

public enableInput = [];

getInputState() {
    // checkboxStatus sets to true if at least one checkbox is checked
    const checkboxStatus = this.enableInput.find(checkboxVal => checkboxVal) ? true : false;
    return checkboxStatus;
}
Related