Angular Validators
Table of Contents
- How it works
- 1.1 Template-driven Forms
- 1.2 Reactive Forms
- Built-in Validators in Angular
- 2.1 Required Validator
- 2.2 Min and Max Length Validators
- 2.3 Pattern Validator
- 2.4 Email Validator
- 2.5 Custom Validators
- Asynchronous Validators
- Combining Validators
- Group Validation
- Summary
1. How it works
In Angular, there are two ways to create forms: template-driven forms
and reactive forms
. Both types of forms can be validated using Angular's built-in validators or custom validators.
1.1 Template-driven Forms
Template-driven forms rely on Angular templates for form creation and validation. Let's create a simple template-driven form with a required field.
<!-- app.component.html -->
<form #myForm="ngForm">
<label for="username">Username:</label>
<input type="text" id="username" name="username" ngModel required>
<div *ngIf="myForm.controls['username'].invalid && (myForm.controls['username'].dirty || myForm.controls['username'].touched)">
<div *ngIf="myForm.controls['username'].errors?.required">Username is required.</div>
</div>
<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
- We use the
ngModel
directive for two-way data binding on theusername
input field. - The
required
attribute ensures that the field is required. - We display an error message if the username is required and the field is dirty or touched.
1.2 Reactive Forms
Reactive forms are built programmatically using TypeScript. Let's create a reactive form with a required field.
// app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = this.fb.group({
username: ['', Validators.required]
});
}
onSubmit() {
// Handle form submission
console.log('Form submitted:', this.myForm.value);
}
}
<!-- app.component.html -->
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<label for="username">Username:</label>
<input type="text" id="username" formControlName="username">
<div *ngIf="myForm.get('username').hasError('required') && (myForm.get('username').dirty || myForm.get('username').touched)">
Username is required.
</div>
<button type="submit" [disabled]="myForm.invalid">Submit</button>
</form>
- We use the
FormBuilder
service to create aFormGroup
with aFormControl
for theusername
field. - Validators are applied to the
username
control, ensuring it is required. - Error messages are displayed based on the control's state.
2. Built-in Validators in Angular
Angular comes with a set of built-in validators that cover common use cases.
2.1 Required Validator
// Example: Adding a required validator to a form control
this.myForm = this.fb.group({
username: ['', Validators.required],
});
2.2 Min and Max Length Validators
// Example: Adding min and max length validators
this.myForm = this.fb.group({
password: ['', [Validators.minLength(6), Validators.maxLength(10)]],
});
2.3 Pattern Validator
// Example: Using a regular expression pattern validator
this.myForm = this.fb.group({
phone: ['', [Validators.pattern(/^(\+\d{1,2}\s?)?(\d{10})$/)]],
});
2.4 Email Validator
// Example: Applying the email validator
this.myForm = this.fb.group({
email: ['', Validators.email],
});
2.5 Custom Validators
import { AbstractControl, ValidationErrors } from "@angular/forms";
/**
* lowerCaseValidator
* Validates that the value has at least one lower case character.
*
* @param control - The AbstractControl to validate.
* @returns ValidationErrors or null if the validation passes.
*/
export const lowerCaseValidator = (control: AbstractControl): ValidationErrors | null => {
const value = control.value ;
if (!value) {
return null;
}
const hasLowerCase = /[a-z]+/.test(value);
if (hasLowerCase){
return null
}
return { hasLowerCase: true }
};
this.myForm = this.fb.group({
customField: ['', lowerCaseValidator],
});
Read more about custom validators in the Custom Validators section.
3. Asynchronous Validators
Asynchronous validators are useful when validation involves asynchronous operations, such as checking data against a server.
import { AbstractControl, ValidationErrors } from "@angular/forms";
// Example: Asynchronous validation using a service
function asyncValidator(service: MyService) {
return (control: AbstractControl): Observable<ValidationErrors | null> => {
return service.checkAvailability(control.value).pipe(
map((isAvailable) => (isAvailable ? null : { notAvailable: true }))
);
};
}
this.myForm = this.fb.group({
asyncField: [
'',
[Validators.required],
[asyncValidator(myService),],
updateOn: 'blur', // 'change' or 'blur' or 'submit' - Specifies when the form should be updated
],
});
4. Combining Validators
Validators can be combined for more complex scenarios.
// Example: Combining multiple validators
this.myForm = this.fb.group({
combinedField: [
'',
[Validators.required, Validators.minLength(3), customValidator],
],
});
5. Group Validation
Group validation involves validating the relationship between multiple fields. For example, a password and confirm password field.
// Example: Cross-field validation
function matchingPasswords(
control: AbstractControl
): ValidationErrors | null {
const password = control.get('password');
const confirmPassword = control.get('confirmPassword');
return password.value === confirmPassword.value
? null
: { passwordsNotMatch: true };
}
this.myForm = this.fb.group(
{
password: ['', Validators.required],
confirmPassword: ['', Validators.required],
},
{ validator: matchingPasswords }
);
6. Summary
- Angular provides a set of built-in validators that cover common use cases.
- Validators can be combined for more complex scenarios.
- Custom validators can be created to handle specific use cases.
- Asynchronous validators are useful when validation involves asynchronous operations, such as checking data against a server.
- Cross-field validation involves validating the relationship between multiple fields.