Angular2 模板驱动的异步验证器
Posted
技术标签:
【中文标题】Angular2 模板驱动的异步验证器【英文标题】:Angular2 template driven async validator 【发布时间】:2016-07-14 02:59:42 【问题描述】:我在以模板驱动形式定义异步验证器时遇到问题。
目前我有这个输入:
<input type="text" ngControl="email" [(ngModel)]="model.applicant.contact.email" #email="ngForm" required asyncEmailValidator>
带有指向此类的验证器选择器 asyncEmailValidator:
import provide from "angular2/core";
import Directive from "angular2/core";
import NG_VALIDATORS from "angular2/common";
import Validator from "angular2/common";
import Control from "angular2/common";
import AccountService from "../services/account.service";
@Directive(
selector: '[asyncEmailValidator]',
providers: [provide(NG_VALIDATORS, useExisting: EmailValidator, multi: true), AccountService]
)
export class EmailValidator implements Validator
//https://angular.io/docs/ts/latest/api/common/Validator-interface.html
constructor(private accountService:AccountService)
validate(c:Control):[key: string]: any
let EMAIL_REGEXP = /^[-a-z0-9~!$%^&*_=+\'?]+(\.[-a-z0-9~!$%^&*_=+\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]1,3\.[0-9]1,3\.[0-9]1,3\.[0-9]1,3))(:[0-9]1,5)?$/i;
if (!EMAIL_REGEXP.test(c.value))
return validateEmail: valid: false;
return null;
/*return new Promise(resolve =>
this.accountService.getUserNames(c.value).subscribe(res =>
if (res == true)
resolve(null);
else
resolve(validateEmailTaken: valid: false);
));*/
电子邮件正则表达式部分按预期工作,如果正则表达式匹配,则表单正在成功验证。但在那之后我想检查电子邮件是否还没有被使用,所以我为我的 accountService 创建了承诺。但这根本不起作用,表单一直处于失败状态。
我已经阅读了有关模型驱动表单和使用 FormBuilder 的信息,如下所示:
constructor(builder: FormBuilder)
this.email = new Control('',
Validators.compose([Validators.required, CustomValidators.emailFormat]), CustomValidators.duplicated
);
在 Control() 的第三个参数中定义了异步验证器,但这不是我的情况,因为我使用不同的方法。
所以,我的问题是:是否可以使用模板驱动的表单创建异步验证器?
【问题讨论】:
【参考方案1】:您可以尝试使用NG_ASYNC_VALIDATORS
键而不是NG_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);
));
在 angular.io 网站上查看此文档:
https://angular.io/docs/ts/latest/api/forms/index/NG_ASYNC_VALIDATORS-let.html【讨论】:
谢谢!这正是我想要的。顺便提一句。是否可以在一个验证器类中将验证器的异步部分(承诺)与 noasync 部分(只是正则表达式)结合起来,这样只有当正则表达式正常时才会启动异步部分,还是我需要它们两个? 是的,你可以,但在这两种情况下你都需要解决这个承诺。即使处理不是异步的,后者也可以解决...... 好的,我试试。再次感谢。 感谢您在 angular.io/guide/form-validation 现有文档的基础上构建,这对您有很大帮助!【参考方案2】:值得注意的是,从那时起语法发生了变化,现在我使用的是 angular 4,下面是重写:
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);
));
【讨论】:
【参考方案3】:我能够使用用户服务正确调用 validate 自定义验证器。我遇到的一个问题是,我将自定义验证器保存在 Validators.compose() 中。取出 compose 功能后一切正常。
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);
【讨论】:
以上是关于Angular2 模板驱动的异步验证器的主要内容,如果未能解决你的问题,请参考以下文章