Angular  

Angular Reactive Forms – Dynamic Validation with Real-Time Issue and Fix

This article explains how to handle dynamic form validation in Angular Reactive Forms. It shares a real-world scenario where validation rules need to change based on user input like requiring a PAN number for individuals and a company name for organizations.

The article highlights a common mistake developers make: forgetting to call updateValueAndValidity() after setting or clearing validators, which causes the form to behave unexpectedly. It walks through the issue, shows the incorrect and corrected code, and provides a reusable custom validator for PAN format.

Overall, this article helps developers understand how to implement clean, dynamic validation logic in Angular forms with a practical example and real-time bug resolution.

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.