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); }}