Enterprise applications require highly dynamic and heavily validated forms.
We previously explored the basics of Reactive Forms using FormGroup and FormControl.
Now, we will explore advanced concepts like FormArray and Custom Validators.
Sometimes, you do not know how many input fields a user will need.
For example, allowing a user to add multiple different phone numbers or email addresses dynamically.
Angular provides FormArray to handle arrays of form controls that can grow or shrink at runtime.
import { FormArray, FormControl, FormGroup } from '@angular/forms';
export class ProfileComponent {
profileForm = new FormGroup({
aliases: new FormArray([ new FormControl('Hero') ])
});
get aliases() {
return this.profileForm.get('aliases') as FormArray;
}
addAlias() {
// Dynamically adds a new input field to the form!
this.aliases.push(new FormControl(''));
}
}
Angular provides built-in validators like Validators.required and Validators.email.
However, business logic often requires custom validation rules, like checking if a username is already taken.
You can create custom validators by writing a simple function that returns an error object if the validation fails.
import { AbstractControl, ValidationErrors } from '@angular/forms';
// A custom validator preventing the word "admin"
export function forbiddenNameValidator(control: AbstractControl): ValidationErrors | null {
const forbidden = /admin/i.test(control.value);
// Returns an error object if invalid, or null if valid
return forbidden ? { forbiddenName: { value: control.value } } : null;
}
// Applying it to a FormControl
const username = new FormControl('', [forbiddenNameValidator]);
Sometimes validation depends on multiple fields simultaneously.
A classic example is confirming that a "Password" field and a "Confirm Password" field match exactly.
To achieve this, you attach a custom validator to the parent FormGroup instead of individual FormControls.
export const passwordMatchValidator: ValidatorFn = (control: AbstractControl) => {
const password = control.get('password');
const confirm = control.get('confirmPassword');
return password && confirm && password.value !== confirm.value
? { mismatch: true } : null;
};
Which Angular class is specifically designed to manage a dynamic, resizable list of form controls?
What must a custom validator function return if the form control's value is perfectly valid?