When you need to query the database or hit your API you need to wait for the result to return.
This validator expects a boolean as a return value from the back-end.
slow.async-validator.ts
import { Injectable } from '@angular/core'; import { AbstractControl, ValidationErrors } from '@angular/forms'; import { Observable, of } from 'rxjs'; import { delay, map } from 'rxjs/operators'; @Injectable( { providedIn: 'root' } ) /** * Returns undefined after a delay of 1 second */ export class SlowValidator { constructor() { } validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> { // Inject a service in the constructor and do a call & map it: return of(undefined) .pipe( map((value: any) => { return (value) ? { asyncValue: true } : undefined); }, catchError(() => { asyncValue: true }) ) ); } registerOnValidatorChange?(fn: () => void): void { throw new Error('Method not implemented.'); } }
slow.component.ts
import { Component } from '@angular/core'; import { FormGroup, Validators, FormBuilder } from '@angular/forms'; import { SlowValidator } from './validators/Eslow.async-validator'; @Component({ selector: 'app-async-validators', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class SlowComponent { constructor( private _fb: FormBuilder, private _slowValidator: SlowValidator, ) { } this.form = this._fb.group({ field: ['', [ // Regular. Validators.required, ], [ // Async. this._slowValidator.validate.bind(this._slowValidator) ] ] }); } }
component.html
<form novalidate [formGroup]="form"> <input type="text" formControlName="field" /> <div *ngIf="form.get('field').errors?.asyncValue"> The validator did not return 'undefined', so there is an error </div> </form>