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

时间:2017-01-05 09:45:02

标签: templates angular angular2-forms angular2-directives

我的模型驱动表单中有一个自定义验证器,用于验证。

模板 -

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

这适用于模型驱动表单

但是如何对模板驱动使用相同的验证功能

我正在关注此链接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>

我得到无法读取属性&#39; hasError&#39;未定义的。

3 个答案:

答案 0 :(得分:3)

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

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可供您使用。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

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">

希望这两个例子能帮到你