如何在基于模型和模板的控制器中使用相同的验证器

How to use the Same Validator in Model and Template Based Controllers

我的模型驱动表单中有一个自定义验证器来执行验证。

模板 -

<form [formGroup] = "myForm" (ngSubmit) = "save(myForm.value)">

            <div>
                <label>Name</label>
                <input type="text" formControlName="name">
            </div>
             <p *ngIf="myForm.controls.name?.errors">This has to be rahulsingh!</p>
             <button type = "submit" > Submit</button>
        </form>

组件 -

this.myForm = this.fb.group({
            name: ['', [this.validateName]]          
        });


validateName(c: FormControl) {
    return (c.value === 'rahulSingh') ? null : {
        notCorrect: true
    };
}

这适用于模型驱动表单

但是如何为模板驱动使用相同的验证函数

我正在关注这个 link http://blog.thoughtram.io/angular/2016/03/21/template-driven-forms-in-angular-2.html

但我无法理解如何使此函数对两种形式都全局化并将其用作指令。我总是在尝试实现这一目标时遇到奇怪的错误。

当我尝试做时,我的模板中还有一件奇怪的事情

<p *ngIf="myForm.hasErrors('notCorrect')">This has to be rahulsingh!</p>

我无法读取未定义的 属性 'hasError' .

您可以使用与类相同的方式导出函数:

export const validateName:ValidateFn = (c: FormControl) {
    return (c.value === 'rahulSingh') ? null : {
        notCorrect: true
    };
}

然后导入它们:

    import {validateName} from '...';

    this.myForm = this.fb.group({
        name: ['', [validateName]]    
    });

本教程可能会有所帮助How to Implement a Custom Validator Directive

下面给出了电子邮件验证的指令

import { Directive, forwardRef } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';

@Directive({
  selector: '[validateEmail]',
  providers: [{ provide: NG_VALIDATORS, useExisting: forwardRef(() => ValidateEmail), multi: true }]
})
export class ValidateEmail implements Validator {

  constructor() { }

  validate(c: AbstractControl): { [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 (!c.value) return null;
    return EMAIL_REGEXP.test(c.value) ? null : {
      validEmail: true
    };
  }
}

下面是另一个用于将模型与另一个模型匹配的自定义验证指令。

import { Directive, ElementRef, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS, FormControl } from '@angular/forms';

@Directive({
  selector: '[matchControl][ngModel]',
  providers: [{ provide: NG_VALIDATORS, useExisting: forwardRef(() => MatchControl), multi: true }]
})
export class MatchControl implements Validator{

  constructor(@Attribute('matchControl') private matchControl: string) { }

  validate(c: AbstractControl): { [key: string]: any; } {
    let v = c.value;
    let e = c.root.get(this.matchControl)

    return (e && v !== e.value) ? {
        match: true
    } : null;
  }
}

及其html如下

<input name="password" type="password" class="form-control" required minlength="8" maxlength="15" [(ngModel)]="user.password" #password="ngModel">
<input name="cpassword" type="password" class="form-control" required [(ngModel)]="user.cpassword" #cpassword="ngModel" matchControl="password">

希望这两个例子对您有所帮助

首先,我们将构建适用于模板驱动表单的指令,该指令将自动使其适用于响应式表单(巧妙的技巧):

import { Directive, Input } from '@angular/core';
import { FormControl, NG_VALIDATORS, Validator } from '@angular/forms';

@Directive({
  selector: '[requiredName][ngModel]',
  providers: [{provide: NG_VALIDATORS, useExisting: SpecificNameValidatorDirective, multi: true}]
})
export class SpecificNameValidatorDirective implements Validator {
  private valFn = (c: FormControl, name: string) {
    return (c.value === name) ? null : {
        notCorrect: true
    };
  }

  @Input('requiredName') name: string = "temp";

  constructor() {
  }

  validate(control: AbstractControl): {[key: string]: any} {
    console.log("validation station", this.name, control.value);
    return this.valFn(control, this.name);
  }
}

这里的名称不是硬编码的,但提供了默认值,这意味着我们可以像这样以模板驱动的形式使用该指令:

<form #myForm="ngForm" (ngSubmit)="save(myForm.value)">
    <div>
        <label>Name</label>
        <input requiredName="rahulSingh" name="name" ngModel #name="ngModel" type="text" id="name">
    </div>
     <p *ngIf="name.errors?.notCorrect">This has to be rahulSingh!</p>
     <button type="submit"> Submit</button>
</form>

模板驱动表单足够简单。

对于 Reactive Form 我们可以实例化一个指令的实例:

var validator = new SpecificNameValidatorDirective();

然后设置我们想要的名字

validator.name = "nobdy";

然后使用我们的指令实例构建我们的表单:

this.myForm = this.fb.group({
          name: ['',[validator]]
      });

这将自动查找 validate 函数并执行它,因为各种验证器都遵循 Validator interface definition。 janky 部分是在单独的行中而不是在构造函数中设置名称,但我无法使它与模板驱动版本一起玩得很好。

总之,有一个 Plunker 可以让你玩。