اعتبارسنجی - اعتبارسنج ناهمزمان مبتنی بر قالب در Angular2


من با تعریف اعتبارسنج ناهمزمان در فرم مبتنی بر قالب مشکل دارم.

در حال حاضر من این ورودی را دارم:

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

}

قسمت regex ایمیل همانطور که انتظار میرود کار میکند و فرم بهطور موفقیتآمیز در صورتی که regex مطابقت داشته باشد اعتبارسنجی میشود. اما بعد از آن میخواهم بررسی کنم که آیا ایمیل قبلاً استفاده نشده است، بنابراین برای accountService خود یک Promise ایجاد میکنم. اما این اصلاً کار نمیکند و فرم همیشه در حالت ناموفق است.

من در مورد فرمهای مبتنی بر مدل و استفاده از FormBuilder به شرح زیر مطالعه کردهام:

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

کدامها ولیدیتورهای غیرهمزمان را در پارامتر سوم Control() تعریف کردهاند، اما این مورد من نیست زیرا من از روش متفاوتی استفاده میکنم.

پس سوال من این است: آیا امکان ایجاد اعتبارسنج غیرهمزمان با استفاده از فرمهای مبتنی بر قالب وجود دارد؟

پاسخ شماره ۱

شما میتوانید سعی کنید ارائهدهنده اعتبارسنج غیرهمزمان خود را با کلید 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

پاسخ شماره ۲

شایان ذکر است که نحو از آن زمان تغییر کرده است، اکنون من از انگولار ۴ استفاده میکنم، و در زیر بازنویسی آمده است:

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