See step-by-step how to create a custom validator in a reactive Angular form with a login screen that requires a confirmation password to match the original password.
In Angular, you can create a form in two ways:
This post will teach you to implement custom cross-control validator in a reactive form. One example of cross-validation could be password-confirm password validation, which we will implement.
Let us start with creating a login form. To do that:
fb = inject(FormBuilder);
loginForm: FormGroup;
constructor() {
this.loginForm = this.fb.group({
email: [null, [Validators.required]],
password: [null, [Validators.required]],
confirmPassword: []
})
}
On the template, map the loginForm to the HTML Form element and FormControls to the input elements.
<form (ngSubmit)="login()" [formGroup]="loginForm" novalidate>
<input type="text" formControlName="email" placeholder="Enter email" />
<br/>
<input type="password" formControlName="password" placeholder="Enter Password"/>
<br/>
<input type="text" formControlName="confirmPassword" placeholder="Confirm Password"/>
<br/>
<button>Login</button>
</form>
We call the login()
function at the click of the button, and inside that we print the form’s value and status.
login(){
console.log(this.loginForm.value);
console.log(this.loginForm.valid);
}
So far, we have created the login form, which should look like the image below.
After entering the values, when you click on the Login button, you see that values of the Password and Confirm Password fields are different, but the form’s status is valid.
Add a file to create a custom validator for the Password and Confirm Password fields.
We are going to put the validator function in this file. A custom validator function follows a fixed syntax.
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms"
export const PasswordValidator: ValidatorFn = (control:AbstractControl): ValidationErrors| null =>{
return null;
}
The type of custom validator function is ValidatorFn, which is defined below.
* @publicApi
*/
export declare interface ValidatorFn {
(control: AbstractControl): ValidationErrors | null;
}
Next, in the PasswordValidator
function, write the logic for the custom validator.
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms"
export const PasswordValidator: ValidatorFn = (control:AbstractControl): ValidationErrors| null =>{
const password = control.get('password');
const confirmpassword = control.get('confirmPassword');
if(password && confirmpassword && password.value != confirmpassword.value){
return {
passwordmatcherror : true
}
}
return null;
}
As you see, we have very straightforward logic for the validator.
Now to use the custom validator function PasswordValidator
in the loginForm, pass it to the Validators property of AbstractControlOptions.
this.loginForm = this.fb.group({
email: [null, [Validators.required]],
password: [null, [Validators.required]],
confirmPassword: []
},
{validators:PasswordValidator} as AbstractControlOptions
)
The FormBuilder’s group method takes two objects’ input parameters:
As we have passed above, you can pass Form Group level validators in the options. Next on the template, you can display an error message on the failed validation, as shown in the next code block:
<input type="text" formControlName="confirmPassword" placeholder="Confirm Password"/>
<span *ngIf="loginForm?.errors?.['passwordmatcherror']">Password does not match</span>
Angular complains about it when the password and confirm password fields do not match.
In this way, you can create a cross-control custom validator in Angular.
I hope you liked this article. Thanks for reading.
Dhananjay Kumar is an independent trainer and consultant from India. He is a published author, a well-known speaker, a Google Developer Expert, and a 10-time winner of the Microsoft MVP Award. He is the founder of geek97, which trains developers on various technologies so that they can be job-ready, and organizes India's largest Angular Conference, ng-India. He is the author of the best-selling book on Angular, Angular Essential. Find him on Twitter or GitHub.