简体   繁体   English

Angular2模板驱动的异步验证器

[英]Angular2 template driven async validator

I have a problem with defining asynchrous validator in template driven form. 我在模板驱动形式中定义异步验证器时遇到问题。

Currently i have this input: 目前我有这样的输入:

<input type="text" ngControl="email"  [(ngModel)]="model.applicant.contact.email" #email="ngForm" required asyncEmailValidator>

with validator selector asyncEmailValidator which is pointing to this class: 使用指向此类的验证器选择器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}});
            }
        }));*/
}

} }

Email regex part is working as expected and form is being validated successfuly if regex is matching. 电子邮件正则表达式部分正在按预期工作,如果正则表达式匹配,表单正在成功验证。 But after that I want to check if e-mail is not already in use, so im creating promise for my accountService. 但之后我想检查电子邮件是否尚未使用,因此我为我的accountService创建了承诺。 But this doesn't work at all and form is in failed state all the time. 但这根本不起作用,形式一直处于失败状态。

I've read about model driven forms and using FormBuilder as below: 我已经阅读了关于模型驱动的表单并使用FormBuilder如下:

constructor(builder: FormBuilder) {
this.email = new Control('',
  Validators.compose([Validators.required, CustomValidators.emailFormat]), CustomValidators.duplicated
);
}

Which have async validators defined in third parameter of Control() But this is not my case because im using diffrent approach. 哪个在Control()的第三个参数中定义了异步验证器但是这不是我的情况,因为我使用了不同的方法。

So, my question is: is it possible to create async validator using template driven forms? 所以,我的问题是:是否可以使用模板驱动的表单创建异步验证器?

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): 你可以尝试注册与您的异步验证的提供商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}});
        }
    }));
  }
}

See this doc on the angular.io website: 在angular.io网站上查看此文档:

worth noting that the syntax has changed since then, now i am using angular 4, and here below a rewrite: 值得注意的是,从那时起语法已经改变,现在我使用的是角度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);
                }
            }));
    }
}

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(). 我得到的一个问题是,我将自定义验证器保存在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);
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM