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.