The Validators class provides a set of built-in validators that can be used by form controls. A validator is a function that processes a FormControl or collection of controls and returns an error map or null. A null map means that validation has passed.
Import
import { Validators } from '@angular/forms';
Built-in Validators
required
Validator that requires the control have a non-empty value.
import { FormControl, Validators } from '@angular/forms';
const control = new FormControl('', Validators.required);
console.log(control.errors); // { required: true }
control.setValue('value');
console.log(control.errors); // null
An error map with the required property if the validation check fails, otherwise null.
requiredTrue
Validator that requires the control’s value be true. This validator is commonly used for required checkboxes.
const acceptTerms = new FormControl(false, Validators.requiredTrue);
console.log(acceptTerms.errors); // { required: true }
acceptTerms.setValue(true);
console.log(acceptTerms.errors); // null
An error map with the required property set to true if the validation check fails, otherwise null.
email
Validator that requires the control’s value pass an email validation test.
The validator uses a regular expression pattern based on the WHATWG HTML specification with enhancements:
- Disallows
local-part to begin or end with a period (.)
- Disallows
local-part to be longer than 64 characters
- Disallows the whole address to be longer than 254 characters
const emailControl = new FormControl('', Validators.email);
emailControl.setValue('invalid');
console.log(emailControl.errors); // { email: true }
emailControl.setValue('[email protected]');
console.log(emailControl.errors); // null
An error map with the email property if the validation check fails, otherwise null.
min()
Validator that requires the control’s value to be greater than or equal to the provided number.
const ageControl = new FormControl(2, Validators.min(3));
console.log(ageControl.errors); // { min: { min: 3, actual: 2 } }
ageControl.setValue(5);
console.log(ageControl.errors); // null
A validator function that returns an error map with the min property if the validation check fails, otherwise null.
max()
Validator that requires the control’s value to be less than or equal to the provided number.
const scoreControl = new FormControl(16, Validators.max(15));
console.log(scoreControl.errors); // { max: { max: 15, actual: 16 } }
scoreControl.setValue(10);
console.log(scoreControl.errors); // null
A validator function that returns an error map with the max property if the validation check fails, otherwise null.
minLength()
Validator that requires the number of items in the control’s value to be greater than or equal to the provided minimum length.
This validator is intended for types that have a numeric length or size property, such as strings, arrays, or sets. The validator logic is not invoked for values when their length or size property is 0.
const nameControl = new FormControl('ab', Validators.minLength(3));
console.log(nameControl.errors);
// { minlength: { requiredLength: 3, actualLength: 2 } }
nameControl.setValue('abc');
console.log(nameControl.errors); // null
<!-- Also available as HTML attribute -->
<input minlength="5">
A validator function that returns an error map with the minlength property if the validation check fails, otherwise null.
maxLength()
Validator that requires the number of items in the control’s value to be less than or equal to the provided maximum length.
This validator is intended for types that have a numeric length or size property, such as strings, arrays, or sets.
const nameControl = new FormControl('Angular', Validators.maxLength(5));
console.log(nameControl.errors);
// { maxlength: { requiredLength: 5, actualLength: 7 } }
nameControl.setValue('Ng');
console.log(nameControl.errors); // null
<!-- Also available as HTML attribute -->
<input maxlength="10">
A validator function that returns an error map with the maxlength property if the validation check fails, otherwise null.
pattern()
Validator that requires the control’s value to match a regex pattern.
A regular expression to test the values, or a string. If a string is passed, the ^ character is prepended and the $ character is appended (if not already present).
const codeControl = new FormControl('123', Validators.pattern('[a-zA-Z ]*'));
console.log(codeControl.errors);
// { pattern: { requiredPattern: '^[a-zA-Z ]*$', actualValue: '123' } }
codeControl.setValue('abc');
console.log(codeControl.errors); // null
<!-- Also available as HTML attribute -->
<input pattern="[a-zA-Z ]*">
Do not use the g (global) or y (sticky) flags with Validators.pattern(). These flags cause RegExp.prototype.test() to preserve the index of the last match, which can produce inconsistent results when validations run consecutively.
// Not recommended (uses global flag)
const control1 = new FormControl('1', Validators.pattern(/foo/g));
// Good
const control2 = new FormControl('1', Validators.pattern(/foo/));
A validator function that returns an error map with the pattern property if the validation check fails, otherwise null.
nullValidator()
Validator that performs no operation.
const control = new FormControl('', Validators.nullValidator);
console.log(control.errors); // null
Composing Validators
compose()
Composes multiple validators into a single function that returns the union of the individual error maps.
validators
(ValidatorFn | null | undefined)[]
required
An array of validator functions to compose.
const passwordValidator = Validators.compose([
Validators.required,
Validators.minLength(8),
Validators.pattern(/[A-Z]/), // Must contain uppercase
Validators.pattern(/[0-9]/) // Must contain number
]);
const passwordControl = new FormControl('', passwordValidator);
A validator function that returns an error map with the merged error maps of the validators if the validation check fails, otherwise null.
composeAsync()
Composes multiple async validators into a single function that returns the union of the individual error objects.
validators
(AsyncValidatorFn | null)[]
required
An array of async validator functions to compose.
import { AbstractControl, ValidationErrors } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { delay, map } from 'rxjs/operators';
function usernameValidator(control: AbstractControl): Observable<ValidationErrors | null> {
return checkUsername(control.value).pipe(
map(exists => exists ? { usernameTaken: true } : null)
);
}
function emailValidator(control: AbstractControl): Observable<ValidationErrors | null> {
return checkEmail(control.value).pipe(
map(exists => exists ? { emailTaken: true } : null)
);
}
const asyncValidator = Validators.composeAsync([
usernameValidator,
emailValidator
]);
const control = new FormControl('', {
validators: Validators.required,
asyncValidators: asyncValidator
});
A validator function that returns an error map with the merged error objects if the validation check fails, otherwise null.
Using Multiple Validators
You can apply multiple validators to a single control:
const control = new FormControl('', [
Validators.required,
Validators.minLength(3),
Validators.maxLength(20),
Validators.pattern(/^[a-zA-Z0-9]+$/)
]);
Or using the options object:
const control = new FormControl('', {
validators: [
Validators.required,
Validators.email
],
asyncValidators: customAsyncValidator,
updateOn: 'blur'
});
Custom Validators
Creating a Custom Validator
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
function forbiddenNameValidator(forbiddenName: string): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const forbidden = control.value?.toLowerCase() === forbiddenName.toLowerCase();
return forbidden ? { forbiddenName: { value: control.value } } : null;
};
}
const nameControl = new FormControl('', [
Validators.required,
forbiddenNameValidator('admin')
]);
nameControl.setValue('admin');
console.log(nameControl.errors);
// { forbiddenName: { value: 'admin' } }
Custom Async Validator
import { AbstractControl, ValidationErrors, AsyncValidatorFn } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { map, catchError, debounceTime, switchMap } from 'rxjs/operators';
function uniqueUsernameValidator(userService: UserService): AsyncValidatorFn {
return (control: AbstractControl): Observable<ValidationErrors | null> => {
if (!control.value) {
return of(null);
}
return of(control.value).pipe(
debounceTime(500),
switchMap(username => userService.checkUsername(username)),
map(exists => exists ? { usernameTaken: true } : null),
catchError(() => of(null))
);
};
}
const usernameControl = new FormControl('', {
validators: [Validators.required, Validators.minLength(3)],
asyncValidators: uniqueUsernameValidator(userService)
});
Cross-Field Validation
import { FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';
function passwordMatchValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const password = control.get('password');
const confirmPassword = control.get('confirmPassword');
if (!password || !confirmPassword) {
return null;
}
return password.value === confirmPassword.value
? null
: { passwordMismatch: true };
};
}
const form = new FormGroup(
{
password: new FormControl('', [Validators.required, Validators.minLength(8)]),
confirmPassword: new FormControl('', Validators.required)
},
{ validators: passwordMatchValidator() }
);
console.log(form.errors); // { passwordMismatch: true } if passwords don't match
Validation Errors
Each validator returns a ValidationErrors object when validation fails:
type ValidationErrors = {
[key: string]: any;
};
Checking for Specific Errors
const control = new FormControl('', [
Validators.required,
Validators.minLength(5)
]);
if (control.hasError('required')) {
console.log('This field is required');
}
if (control.hasError('minlength')) {
const error = control.getError('minlength');
console.log(`Minimum length is ${error.requiredLength}, but got ${error.actualLength}`);
}
Dynamic Validators
You can add or remove validators dynamically:
const control = new FormControl('');
// Add validators
control.setValidators([Validators.required, Validators.email]);
control.updateValueAndValidity();
// Add more validators
control.addValidators(Validators.minLength(5));
control.updateValueAndValidity();
// Remove validators
control.removeValidators(Validators.required);
control.updateValueAndValidity();
// Clear all validators
control.clearValidators();
control.updateValueAndValidity();
Validator Directives
You can create custom validator directives for template-driven forms:
import { Directive } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
@Directive({
selector: '[appForbiddenName]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: ForbiddenNameDirective,
multi: true
}
]
})
export class ForbiddenNameDirective implements Validator {
validate(control: AbstractControl): ValidationErrors | null {
return control.value?.toLowerCase() === 'admin'
? { forbiddenName: true }
: null;
}
}
<input type="text" name="username" ngModel appForbiddenName>
Validation Timing
Control when validation occurs using updateOn:
// Validate on every change (default)
const control1 = new FormControl('', {
validators: Validators.required,
updateOn: 'change'
});
// Validate on blur
const control2 = new FormControl('', {
validators: Validators.required,
updateOn: 'blur'
});
// Validate on form submit
const control3 = new FormControl('', {
validators: Validators.required,
updateOn: 'submit'
});
Injection Tokens
NG_VALIDATORS
Injection token for registering additional synchronous validators.
import { NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[customValidator]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => CustomValidatorDirective),
multi: true
}
]
})
export class CustomValidatorDirective implements Validator {
validate(control: AbstractControl): ValidationErrors | null {
return { custom: true };
}
}
NG_ASYNC_VALIDATORS
Injection token for registering additional asynchronous validators.
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[customAsyncValidator]',
providers: [
{
provide: NG_ASYNC_VALIDATORS,
useExisting: CustomAsyncValidatorDirective,
multi: true
}
]
})
export class CustomAsyncValidatorDirective implements AsyncValidator {
validate(control: AbstractControl): Observable<ValidationErrors | null> {
return of({ custom: true }).pipe(delay(1000));
}
}
See Also