Angular2 template driven async validator Angular2 template driven async validator typescript typescript

Angular2 template driven async validator


You could try to register the provider of your async validator with the NG_ASYNC_VALIDATORS key and not the NG_VALIDATORS one (only for synchronous validators):

@Directive({  selector: '[asyncEmailValidator]',  providers: [    provide(NG_ASYNC_VALIDATORS, { // <------------      useExisting: EmailValidator, multi: true    }),    AccountService  ]})export class EmailValidator implements Validator {  constructor(private accountService:AccountService) {  }  validate(c:Control) {    return new Promise(resolve =>      this.accountService.getUserNames(c.value).subscribe(res => {        if (res == true) {            resolve(null);        }        else {            resolve({validateEmailTaken: {valid: false}});        }    }));  }}

See this doc on the angular.io website:


worth noting that the syntax has changed since then, now i am using angular 4, and here below a rewrite:

import { Directive, forwardRef } from '@angular/core';import { AbstractControl, Validator, NG_ASYNC_VALIDATORS } from '@angular/forms';import { AccountService } from 'account.service';@Directive({    selector: '[asyncEmailValidator]',    providers: [        {            provide: NG_ASYNC_VALIDATORS,            useExisting: forwardRef(() => EmailValidatorDirective), multi: true        },    ]})export class EmailValidatorDirective implements Validator {    constructor(private _accountService: AccountService) {    }    validate(c: AbstractControl) {        return new Promise(resolve =>            this._accountService.isEmailExists(c.value).subscribe(res => {                if (res == true) {                    resolve({ validateEmailTaken: { valid: false } });                }                else {                    resolve(null);                }            }));    }}


I am able to correctly call validate custom validators using user service. One problem i was getting was that, I kept my custom validator inside Validators.compose(). After taking out of the compose function everything works.

import { Directive } from '@angular/core';import { AsyncValidator, AbstractControl, ValidationErrors, NG_ASYNC_VALIDATORS, AsyncValidatorFn } from '@angular/forms';import { Observable } from 'rxjs';import { UserService } from '../Services/user.service';import { map } from 'rxjs/operators';export function UniqueUsernameValidator(userService: UserService): AsyncValidatorFn {    return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {        const q = new Promise((resolve, reject) => {            setTimeout(() => {                userService.isUsernameTaken(control.value).subscribe((data: any) => {                    // console.log('top: ' + data + ' type: ' + typeof data);                    if (data === false) {                        resolve(null);                    } else {                        resolve({                            usernameTaken: {                                valid: true                            }                        });                    }                }, () => {                    resolve({                        usernameTaken: {                            valid: false                        }                    });                });            }, 1000);        });        return q;    };}@Directive({    selector: '[appUniqueUsername]',    providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: UniqueUsernameValidatorDirective, multi: true }, UserService]})export class UniqueUsernameValidatorDirective implements AsyncValidator {    constructor(private userService: UserService) { }    validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {        return UniqueUsernameValidator(this.userService)(control);    }}