如何根据 Angular 2 中的自定义验证规则显示错误消息?
Posted
技术标签:
【中文标题】如何根据 Angular 2 中的自定义验证规则显示错误消息?【英文标题】:How to display error message based on custom validation rules in Angular 2? 【发布时间】:2016-11-28 17:59:35 【问题描述】:我正在使用模板驱动的方法在 Angular 2 中构建表单,并且我已经成功创建了可以在模板中使用的自定义验证器。
但是,我找不到显示绑定到特定错误的特定错误消息的方法。我想区分为什么表格无效。我如何做到这一点?
import Component from '@angular/core';
import NgForm from '@angular/forms';
import Site from './../site';
import BackendService from './../backend.service';
import email from './../validators';
import CustomValidators from './../validators';
@Component(
templateUrl: 'app/templates/form.component.html',
styleUrls: ['app/css/form.css'],
directives: [CustomValidators.Email, CustomValidators.Url, CustomValidators.Goof],
providers: [BackendService]
)
export class FormComponent
active = true;
submitted = false;
model = new Site();
onSubmit()
this.submitted = true;
console.log(this.model);
resetForm()
this.model = new Site();
this.submitted = false;
this.active = false;
setTimeout(() => this.active = true, 0);
get diagnostics()
return JSON.stringify(this.model)
import Directive, forwardRef from '@angular/core';
import NG_VALIDATORS, FormControl from '@angular/forms';
import BackendService from './backend.service';
function validateEmailFactory(backend:BackendService)
return (c:FormControl) =>
let EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`|~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
return EMAIL_REGEXP.test(c.value) ? null :
validateEmail:
valid: false
;
;
export module CustomValidators
@Directive(
selector: '[email][ngModel],[email][formControl]',
providers: [
provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Email), multi: true
]
)
export class Email
validator:Function;
constructor(backend:BackendService)
this.validator = validateEmailFactory(backend);
validate(c:FormControl)
return this.validator(c);
@Directive(
selector: '[url][ngModel],[url][formControl]',
providers: [
provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Url), multi: true
]
)
export class Url
validator:Function;
constructor(backend:BackendService)
this.validator = validateEmailFactory(backend);
validate(c:FormControl)
var pattern = /(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]2,256\.[a-z]2,4\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/;
return pattern.test(c.value) ? null :
validateEmail:
valid: false
;
@Directive(
selector: '[goof][ngModel],[goof][formControl]',
providers: [
provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Goof), multi: true
]
)
export class Goof
validate(c:FormControl)
return
validateGoof:
valid: false
;
【问题讨论】:
【参考方案1】:您可以只检查AbstractControl#hasError(...)
方法来查看控件是否存在特定错误。 FormGroup
和 FormControl
都是 AbstractControl
s。对于FormControl
,您只需将错误名称作为参数传递。例如
function regexValidator(control: FormControl): [key:string]: boolean
if (!control.value.match(/^pee/))
return 'badName': true ;
<div *ngIf="!nameCtrl.valid && nameCtrl.hasError('badName')"
class="error">Name must start with <tt>pee</tt>.
</div>
验证器方法应该返回一个字符串/布尔映射,其中键是错误的名称。这是您在 hasError
方法中检查的名称。
对于FormGroup
,您可以将FormControl
的路径作为额外参数传递。
<div *ngIf="!form.valid && form.hasError('required', ['name'])"
class="error">Form name is required.</div>
name
只是输入的FormControl
的标识符。
这是一个同时使用FormControl
和FormGroup
检查的示例。
import Component from '@angular/core';
import
FormGroup,
FormBuilder,
FormControl,
Validators,
AbstractControl,
REACTIVE_FORM_DIRECTIVES
from '@angular/forms';
function regexValidator(control: FormControl): [key:string]: boolean
if (!control.value.match(/^pee/))
return 'badName': true ;
@Component(
selector: 'validation-errors-demo',
template: `
<div>
<h2>Differentiate Validation Errors</h2>
<h4>Type in "peeskillet"</h4>
<form [formGroup]="form">
<label for="name">Name: </label>
<input type="text" [formControl]="nameCtrl"/>
<div *ngIf="!nameCtrl.valid && nameCtrl.hasError('required')"
class="error">Name is required.</div>
<div *ngIf="!nameCtrl.valid && nameCtrl.hasError('badName')"
class="error">Name must start with <tt>pee</tt>.</div>
<div *ngIf="!form.valid && form.hasError('required', ['name'])"
class="error">Form name is required.</div>
</form>
</div>
`,
styles: [`
.error
border-radius: 3px;
border: 1px solid #AB4F5B;
color: #AB4F5B;
background-color: #F7CBD1;
margin: 5px;
padding: 10px;
`],
directives: [REACTIVE_FORM_DIRECTIVES],
providers: [FormBuilder]
)
export class ValidationErrorsDemoComponent
form: FormGroup;
nameCtrl: AbstractControl;
constructor(formBuilder: FormBuilder)
let name = new FormControl('', Validators.compose([
Validators.required, regexValidator
]));
this.form = formBuilder.group(
name: name
);
this.nameCtrl = this.form.controls['name'];
更新
好的,我让它工作了,但它有点冗长。我不知道如何正确访问输入的个人FormControl
。所以我所做的只是创建一个对FormGroup
的引用
<form #f="ngForm" novalidate>
然后为了检查有效性,我只使用传递表单控件名称路径的hasError
重载。对于使用name
和ngModel
的<input>
,name
值将添加到主FormGroup
中,该名称作为FormControl
名称。所以你可以像这样访问它
`f.form.hasError('require', ['nameCtrl'])`
假设name=nameCtrl
。注意f.form
。 f
是NgForm
实例,它有一个FormGroup
成员变量form
。
下面是重构示例
import Component, Directive from '@angular/core';
import
FormControl,
Validators,
AbstractControl,
NG_VALIDATORS,
REACTIVE_FORM_DIRECTIVES
from '@angular/forms';
function validateRegex(control: FormControl): [key:string]: boolean
if (!control.value || !control.value.match(/^pee/))
return 'badName': true ;
@Directive(
selector: '[validateRegex]',
providers: [
provide: NG_VALIDATORS, useValue: validateRegex, multi: true
]
)
export class RegexValidator
@Component(
moduleId: module.id,
selector: 'validation-errors-template-demo',
template: `
<div>
<h2>Differentiate Validation Errors</h2>
<h4>Type in "peeskillet"</h4>
<form #f="ngForm" novalidate>
<label for="name">Name: </label>
<input type="text" name="nameCtrl" ngModel validateRegex required />
<div *ngIf="!f.form.valid && f.form.hasError('badName', ['nameCtrl'])"
class="error">Name must start with <tt>pee</tt>.</div>
<div *ngIf="!f.form.valid && f.form.hasError('required', ['nameCtrl'])"
class="error">Name is required.</div>
</form>
</div>
`,
styles: [`
.error
border-radius: 3px;
border: 1px solid #AB4F5B;
color: #AB4F5B;
background-color: #F7CBD1;
margin: 5px;
padding: 10px;
`],
directives: [REACTIVE_FORM_DIRECTIVES, RegexValidator]
)
export class ValidationErrorsTemplateDemoComponent
【讨论】:
这很有帮助,但是您正在使用模型驱动的方法来构建表单(使用 FormBuilder)。当我使用模板驱动时,我不知道如何在 html 中公开 AbstractControl 来询问它是否有错误。我总是得到 hasError is not a function 或类似的东西。 在您的模板中,这些模型被隐式创建以表示输入。您仍然可以从模板访问它们,而根本没有任何成员模型变量。您只需要在模板中创建引用变量。如果您发布更完整的示例,我可以尝试帮助您 例如,在您的表单中您可以使用<form #f="ngForm">
,现在f
是代表FormGroup
的变量。 ngForm
是提供的东西,所以你不必担心它来自哪里。同样对于您的不同输入,您可以使用<input #nameInput [formControl]="nameInput">
,并且nameInput
将作为FormControl
添加到f
表单中。有很多不同的方法来设置声明性模板。如果您需要更多帮助,我可能需要在您的模板中查看您的设置
我想要一个带有 1 个输入(以声明方式)的简单表单,它与模型双向绑定,并且我可以访问模板的 AbstractControl 表单以检查其有效性和自定义错误。 [formControl]="nameInput" 抛出 Can't bind to 'formControl' 因为它不是已知的本机属性
查看我的更新。我得到了它的工作,但不是我认为它应该工作的方式。看来我的假设是不正确的。【参考方案2】:
对于模板驱动的验证,使用如下属性指令:
import Model from '../../models';
import Directive, Attribute, forwardRef, Input from '@angular/core';
import NG_VALIDATORS, Validator, AbstractControl from '@angular/forms';
@Directive(
selector: '[unique-in-list][formControlName],[unique-in-list][formControl],[unique-in-list][ngModel]',
providers: [
provide: NG_VALIDATORS, useExisting: forwardRef(() => UniqueInListDirectiveValidator), multi: true
]
)
export class UniqueInListDirectiveValidator implements Validator
@Input('list') private list: Model[];
@Input('property') private _property: string;
@Input('thisid') private _myId: string;
validate(control: AbstractControl): [key: string]: any
let currValue = control.value;
if (currValue && currValue.length > 0 && this.list && Array.isArray(this.list) && this.list.length > 0)
let model = this.list.find(
(testModel: Model) =>
return testModel.modelId !== this._myId && testModel[this._property] === currValue;
);
if (model)
return isUnique: true
return null;
.. 在您的模板中使用随附的标记:
<input
type="text"
#nameVar="ngModel"
name="name"
class="form-control name-field"
unique-in-list
[list]="models"
[thisid]="model.modelId"
property="name"
[(ngModel)]="model.name"
required
/>
<div *ngIf="nameVar.errors?.required && (submitted || !nameVar.pristine)" class="alert-classes-here">
<div>Name is required</div>
</div>
<div *ngIf="nameVar.errors?.isUnique && (submitted || !nameVar.pristine)" class="alert-classes-here">
<div>Name is already taken</div>
</div>
HTH
【讨论】:
【参考方案3】:我从 AngularJs 编写了一组类似于 ng-messages
的指令来解决 Angular 中的这个问题。 https://github.com/DmitryEfimenko/ngx-messages
<div [val-messages]="myForm.get('email')">
<span val-message="required">Please provide email address</span>
<span val-message="server" useErrorValue="true"></span>
</div>
【讨论】:
以上是关于如何根据 Angular 2 中的自定义验证规则显示错误消息?的主要内容,如果未能解决你的问题,请参考以下文章