【问题标题】:Angular2 template driven async validatorAngular2 模板驱动的异步验证器
【发布时间】: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() 的第三个参数中定义了异步验证器,但这不是我的情况,因为我使用不同的方法。

所以,我的问题是:是否可以使用模板驱动的表单创建异步验证器?

【问题讨论】:

    标签: validation asynchronous typescript angular


    【解决方案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 网站上查看此文档:

    【讨论】:

    • 谢谢!这正是我想要的。顺便提一句。是否可以在一个验证器类中将验证器的异步部分(承诺)与 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);
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2018-04-16
        • 1970-01-01
        • 2017-10-18
        • 1970-01-01
        • 2017-07-10
        • 2017-04-08
        • 2016-09-11
        • 2017-10-23
        • 2016-07-26
        相关资源
        最近更新 更多