The handling of dynamic form validation in Angular Reactive Forms is described in this article. It illustrates a real-world situation in which validation rules must alter in response to user input, such as requiring a company name for corporations and a PAN number for individuals. According to the article, developers frequently make the error of forgetting to call updateValueAndValidity() after updating or clearing validators, which results in unexpected form behavior. It explains the problem, displays the code that was wrong and fixed, and offers a reusable custom validator for PAN format.


 Overall, with a useful example and real-time bug fixes, this article assists developers in understanding how to implement clear, dynamic validation logic in Angular forms.

Overview
Angular’s Reactive Forms module gives you fine-grained control over form data, structure, and validation. One of the most useful features is dynamically applying validators based on user input or context.

In real-world applications, dynamic validation is essential, for example, requiring a secondary email only if a checkbox is selected, or validating a PAN number only for Indian users.

Scenario

In one of our insurance applications, we had a registration form with the following fields:

  • User Type (Individual / Organization)
  • PAN Number (Mandatory for Individuals)
  • Company Name (Mandatory for Organizations)

The validation was supposed to change dynamically when the user toggles between "Individual" and "Organization".

Initial Implementation
Here’s the basic structure of the Reactive Form:
this.registrationForm = this.fb.group({
  userType: ['Individual'],
  panNumber: [''],
  companyName: ['']
});


In the onUserTypeChange() method, we tried to manually add/remove validators:
onUserTypeChange(userType: string) {
  if (userType === 'Individual') {
    this.registrationForm.get('panNumber')?.setValidators([
      Validators.required,
      this.panValidator
    ]);
    this.registrationForm.get('companyName')?.clearValidators();
  } else {
    this.registrationForm.get('companyName')?.setValidators([
      Validators.required
    ]);
    this.registrationForm.get('panNumber')?.clearValidators();
  }

  // Missing updateValueAndValidity
}

Real-Time Issue Faced
Despite switching user type, the form still showed both fields as invalid/valid incorrectly.

Root Cause
We forgot to call updateValueAndValidity() after changing the validators. As a result, the validation state wasn’t recalculated.

Fix Implemented
We modified the method to:
onUserTypeChange(userType: string) {
  const panControl = this.registrationForm.get('panNumber');
  const companyControl = this.registrationForm.get('companyName');

  if (userType === 'Individual') {
    panControl?.setValidators([Validators.required, this.panValidator]);
    companyControl?.clearValidators();
  } else {
    companyControl?.setValidators([Validators.required]);
    panControl?.clearValidators();
  }

  panControl?.updateValueAndValidity();
  companyControl?.updateValueAndValidity();
}


Also, we triggered onUserTypeChange() on form initialization to ensure it reflects the default selection.

Real-Time PAN Validator

Here’s how the PAN format validator looked:
panValidator(control: AbstractControl): ValidationErrors | null {
  const panRegex = /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/;

  if (control.value && !panRegex.test(control.value)) {
    return { invalidPAN: true };
  }

  return null;
}

Outcome
The dynamic validation works perfectly now

Fields show real-time validation updates
This pattern is reusable across other forms with dynamic sections

Conclusion

Dynamic form validation is a common need in Angular apps. Always remember:

  • Use setValidators() and clearValidators() as needed
  • Call updateValueAndValidity() after updating validators
  • For complex logic, extract reusable custom validators

This simple oversight (not updating the validity) caused hours of confusion in a production bug. But the lesson helped in building better reactive forms in other modules too.