Home > OS >  How to remove the required validators from Angular input?
How to remove the required validators from Angular input?

Time:09-07

Have been using Angular 13 in my application and have a scenario where I have to remove a required field validation on value changes. Find this stackblitz for a demo of what I am trying to achieve.

In the demo atleast one field is required. If I add firstname, validation on nickname should be removed or vice versa.

Have tried using the updateValueandValidity method but that doesn't seem to work as well. If I do not pass any opts on the updateValueandValidity method, Maximum Call stack error appears as valuechanges is called infinitely. Below is code from stackblitz.

HTML:

   <h1>Mandatory to add atleast one name</h1>
   <form [formGroup]="registerForm">
     <div >
        <mat-form-field>
          <mat-label>First Name</mat-label>
          <input matInput formControlName="firstName" />
        </mat-form-field>
     </div>
     <div >
       <mat-form-field>
         <mat-label>Nick Name</mat-label>
         <input matInput formControlName="nickName" />
       </mat-form-field>
     </div>
  </form>

TS:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  public registerForm: FormGroup;

  ngOnInit() {
    this.registerForm = new FormGroup({
       firstName: new FormControl('', Validators.required),
       nickName: new FormControl('', Validators.required),
    });
    this.toggleRequiredValidationOnInput();
  }
  toggleRequiredValidationOnInput() {
    Object.keys(this.registerForm.controls).forEach((field)=>{
     this.registerForm.get(field)?.valueChanges.subscribe(()=> {
       let isMandatory = false;
       isMandatory = !Object.keys(this.registerForm.controls).some((field) => {
       return this.registerForm.get(field)?.value;
     });
     this.updateFieldWithMandatoryCheck(isMandatory);
   });
 });
}
updateFieldWithMandatoryCheck(isMandatory) {
  Object.keys(this.registerForm.controls).forEach((field) => {
    if (isMandatory) { this.registerForm.get(field).addValidators(Validators.required);
  } else {
    this.registerForm.get(field).removeValidators(Validators.required);
  }
  this.registerForm
    .get(field)
    .updateValueAndValidity({ onlySelf: true, emitEvent: false });
  });
 }
}

CodePudding user response:

Instead of adding/removing the validators manually, you could put a custom cross-field-validator function onto the FormGroup, like this:

private checkAtLeastOneRequired(form: FormGroup): ValidationErrors {
    const ffFirstName: AbstractControl = form.get('firstName');
    const ffNickName: AbstractControl = form.get('nickName');

    let errors: ValidationErrors = null;
    if (!ffFirstName.value && !ffNickName.value) {
        errors = { atLeastOneRequired: true };
    }

    ffFirstName.setErrors(errors);
    ffNickName.setErrors(errors);

    return errors;
}

ngOnInit(): void {
    this.registerForm = new FormGroup({
       firstName: new FormControl(''),
       nickName: new FormControl(''),
    }, this.checkAtLeastOneRequired);
}

CodePudding user response:

Ok, here is what I did. The trick to breaking the loop was using the distinctUntilChanged pipe. See the demo here

ngOnInit() {
    this.registerForm = new FormGroup({
      firstName: new FormControl('', Validators.required),
      nickName: new FormControl('', Validators.required),
    });

    this.registerForm
      .get('firstName')
      .valueChanges.pipe(takeUntil(this.destroy$), distinctUntilChanged())
      .subscribe({
        next: (val) => {
          if (val) {
            this.registerForm.get('nickName').clearValidators();
            this.registerForm.get('nickName').updateValueAndValidity();
          } else {
            this.registerForm
              .get('nickName')
              .setValidators([Validators.required]);
            this.registerForm.get('nickName').updateValueAndValidity();
          }
        },
      });

    this.registerForm
      .get('nickName')
      .valueChanges.pipe(takeUntil(this.destroy$), distinctUntilChanged())
      .subscribe({
        next: (val) => {
          if (val) {
            this.registerForm.get('firstName').clearValidators();
            this.registerForm.get('firstName').updateValueAndValidity();
          } else {
            this.registerForm
              .get('firstName')
              .setValidators([Validators.required]);

            this.registerForm.get('firstName').updateValueAndValidity();
          }
        },
      });
  }
  • Related