如何在基于模型和模板的控制器中使用相同的验证器
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]]
});
下面给出了电子邮件验证的指令
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 可以让你玩。
我的模型驱动表单中有一个自定义验证器来执行验证。
模板 -
<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]]
});
下面给出了电子邮件验证的指令
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 可以让你玩。