In this tutorial , we are going to learn how to create a custom Async validator
in angular .
We will also see how to use the asyncValidatorFn
interface provided by angular to handle async validations and implement our custom async Validator.
Generally , when we use the async
keyword , that means , we are talking about asynchronous communication which will be explained and used in the custom async validator example.
Table of Contents
How To Create Custom Async Validator in Angular ?
Generally , when we create forms, we must control the user inputs to secure the application and also have better user experience by showing the right message to the user.
For example, if the user wants to enter the age, he must not be allowed to put a number < 1 and > 100 , that’s why we use the angular validator to control the user input and show the right error message to the user.
In the previous case , we have used the sync validator
because we can check the input validation in real time.
In some cases , we can’t check the validation because we don’t have the data locally,
For example , if we want to check the email existence when the user enters his email, we need to access the database and check if the email already exists or not.
To do that we just need to create a custom Async validator
and check the email existence using asynchronous API calls.
How To Use Asynchronous Service in Angular ?
In our example , we are going to validate the email input by checking if it exists in the database or not.
To do that we will create a custom async Validator
that uses an asynchronous service to get the data from the database which returns the result as observable
or promise
.
Generally we need to make an API call that returns an observable then we subscribe it in the custom Async validator
.
As we don’t have an Api , we will mock the response and make a fake observable
that returns the same result as the Api call.
import {Observable, of} from "rxjs";
export class UserService {
emailListMock = [
'email_1@gmail.com',
'email_2@gmail.com',
'email_3@gmail.com',
'email_4@gmail.com',
'email_5@gmail.com',
'email_6@gmail.com',
]
isEmailExist(email: string): Observable {
// we can make API call here instead.
const isEmailExist = this.emailListMock.indexOf(email) != -1;
return of(isEmailExist);
}
}
To use the service in our application , we need to add it to the providers of the application module ( check the line 29 bellow)
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {ReactiveFormsModule} from "@angular/forms";
import {MatFormFieldModule} from "@angular/material/form-field";
import {MatInputModule} from "@angular/material/input";
import {MatCardModule} from "@angular/material/card";
import {MatButtonModule} from "@angular/material/button";
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {UserService} from "./service/user-service";
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
MatCardModule,
MatButtonModule,
BrowserAnimationsModule
],
providers: [UserService],
bootstrap: [AppComponent]
})
export class AppModule { }
How To Use AsyncValidatorFn Interface ?
To handle async validations , Angular provides AsyncValidatorFn
Interface that helps us to create custom async validators.
The asyncValidatorFn
interface contains a function declaration that has AbstractControl
as an argument.
The AbstractControl
argument contains the latest formControl
value.
the function that will be implemented must return Observable<ValidationErrors | null>
or Promise<ValidationErrors | null>
In the previous part of the tutorial , we have seen how to implement the service that returns an observable
.
Now , we just need to inject the service into the custom Async validator
and use it inside the function.
import {UserService} from "./user-service";
import {AbstractControl, AsyncValidatorFn, ValidationErrors} from "@angular/forms";
import {debounceTime, Observable, of} from "rxjs";
export function isEmailExistValidator(userService: UserService): AsyncValidatorFn {
return (formControl: AbstractControl): Promise | Observable => {
let emailValidation = null;
userService.isEmailExist(formControl.value)
.pipe(debounceTime(2000))
.subscribe(isEmailExist => {
if (isEmailExist) {
emailValidation = { "isEmailExist": true };
}
})
return of(emailValidation);
};
}
Async Validator using Reactive-forms Approach
Till now , we have the service that returns the observable
and the custom async validator
.
Now , we will build the form structure using the reactive forms approach , that means , we will create the form and handle the validation in the typescript file.
You can also use the template-driven forms approach
So , we will use the formBuilder and formGroup to make the form structure and set the async validator inside.
Then we will add the formControl
elements inside the HTML template and add the error message for each form element.
//app.component.ts
import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
import {isEmailExistValidator} from "./service/email-validator";
import {UserService} from "./service/user-service";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
title = 'Angular Custom Async Validator Example';
userForm: FormGroup = new FormGroup({});
constructor(private formBuilder: FormBuilder, private userService: UserService) {
}
ngOnInit() {
this.initializeForm();
}
initializeForm(): void {
this.userForm = this.formBuilder.group({
pseudo: new FormControl('XperTuto', Validators.required),
name: new FormControl('Aouidane', Validators.required),
email: new FormControl('',
[Validators.required],
[isEmailExistValidator(this.userService)]),
});
}
adduser() {
// call API
console.log(this.userForm.getRawValue());
}
}
We will get someting like that as a result :
References
Clone The Project
To download and run the example, please follow the steps :
1- Clone the source code from XperTuto git repository using the following command :
git clone https://github.com/www-xperTuto-com/Angular-Custom-Async-Validator-Example.git
2- Install the node dependencies using NPM command line : npm install
3- Run the application using the following command : ng serve
4- Access to the project through the URL : http://localhost:4200
Read More About Angular Forms :
Recapitulation
In this tutorial, we have seen how to create a custom Async validator using the reactive-forms approach and we have explained how to use AsyncValidatorFn
that is provided by angular.
We have also seen the difference between the sync validator
and the async validator
and when we should use them exactly through a simple example.
I hope you enjoy reading this Tutorial.