angular2 模板驱动型表单
要使用模板驱动型表单,我们必须先导入FormsModule
模块。
@NgModule({
imports: [
FormsModule, //<==
CommonModule
],
...
})
构造表单获取表单数据
template.component.html
<form #form="ngForm" (ngSubmit)="onSubmit(form.value)">
<div>
<label for="">Name: </label>
<input type="text" name="name" ngModel>
</div>
<div>
<label for="">Password: </label>
<input type="password" name="password" ngModel>
</div>
<button type="submit">Submit</button>
</form>
<div>
{{form.value | json}}
</div>
template.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-template',
templateUrl: './template.component.html'
})
export class TemplateComponent{
constructor() { }
onSubmit(value) {
console.log('submit', value);
}
}
几点说明:
-
angular2
会自动为表单添加ngForm
指令,我们不需要再单独写<form ngForm #form="ngForm" (ngSubmit)="onSubmit(form.value)">
,我们可以通过模板引用变量#form="ngForm"
引用该指令,获取表单的验证信息和数据。 - 当给表单内元素添加
ngModel
指令后,该元素会被自动添加到ngForm
中,我们可以在form.controls
上找到它。要注意的是,使用ngModel
指令时,必须同时给该元素添加name
属性(name="name"
),否则控制台会报错。 - 如果我们确实想使用
ngModel
,又不想给其添加name
属性,我们可以设置[ngModelOptions]="{standalone: true}"
,这样控制台不会报错,但该表单元素不会被添加到ngForm
上。 - 在提交表单时我们可以通过
(ngSubmit)="onSubmit(form.value)"
获取表单内添加了ngModel
指令同时设置了name
属性的表单元素的值。
添加表单验证显示错误信息
假设name
和password
都是必填的,password
长度须在6到12位之间。
template.component.html
<form #form="ngForm" (ngSubmit)="onSubmit(form)">
<div>
<label for="">Name: </label>
<input type="text" name="name" ngModel required #name="ngModel">
<div [style.color]="'red'" *ngIf="name.invalid && (name.dirty || name.touched || form.submitted)">
<p *ngIf="name.errors.required">name can not be empty!</p>
</div>
</div>
<div>
<label for="">Password: </label>
<input type="password" name="password" ngModel required minlength="6" maxlength="12" #password="ngModel">
<div [style.color]="'red'" *ngIf="password.invalid && (password.dirty || password.touched || form.submitted)">
<p *ngIf="password.errors.required">password can not be empty!</p>
<p *ngIf="password.errors.maxlength">the maxlength of password is 12!</p>
<p *ngIf="password.errors.minlength">the minlength of password is 6!</p>
</div>
</div>
<button type="submit">Submit</button>
</form>
几点说明:
-
angular2
内置了一些常见的验证器,required
(必填),maxlength
(最大长度),minlength
(最小长度),max
(最大值),min
(最小值),pattern
(正则表达式)...等等,我们可以直接使用它。 - 我们可以通过模板引用变量
#name="ngModel"
引用ngModel
指令,来获该元素的验证信息,从而做相应的验证提示。 -
*ngIf="name.invalid && (name.dirty || name.touched || form.submitted)"
,这里表示当name
为脏值或者已经被访问过或者表单已经提交了,name
值仍然无效时,显示错误信息,详细的状态说明可参考通过 ngModel 跟踪修改状态与有效性验证。 - 当元素验证失败时,我们可以通过
errors
属性获取具体是那一项验证没有通过,如:*ngIf="name.errors.required"
,表示如果errors
上存在required
属性,表明用户没有输入。
自定义同步验证器
假设我们需要一个可以指定验证规则的密码验证器。
password.validator.ts
import { AbstractControl, NG_VALIDATORS, Validator } from '@angular/forms';
import {Directive, Input} from '@angular/core'
@Directive({
selector:'[password]',
providers: [{provide: NG_VALIDATORS, useExisting: PasswrodDirective, multi: true}]
})
export class PasswrodDirective implements Validator{
@Input()
password:string;
validate(control:AbstractControl) {
let error = null;
if (this.password) {
const reg = new RegExp(this.password, 'i');
if (!reg.test(control.value)) {
error = {
password:control.value
}
}
}
return error;
}
}
在模板中使用
<input type="password" name="password" ngModel password="^[0-9]{6,12}$" #password="ngModel">
<div class="error" [style.color]="'red'" *ngIf="password.invalid && (password.dirty || password.touched || form.submitted)">
<p *ngIf="password.errors.password">password is illegal!</p>
</div>
几点说明:
- 验证器的本质就是一个属性型指令。
-
angular2
内置的验证器都是绑定在NG_VALIDATORS
上的,我们可以通过设置providers
属性对其进行扩展。 - 我们通过
@Input()
给指令添加了一个输入参数,这样我们可以指定验证规则了。 - 该指令的类实现了
Validator
接口,需要实现validate
这个方法。validate
方法接收一个AbstractControl
类型的参数control
,我们可以通过control.value
获取到需要校验的值。validate
方法返回null
表示验证成功,返回对象(这个例子中是:{password:'test'}
)表示验证失败,返回的错误对象的属性会被添加到errors
对象中。
自定义异步验证器
假设我们需要一个可以验证用户名是否重复的验证器。name.validator.ts
import { AbstractControl, AsyncValidator, NG_ASYNC_VALIDATORS } from '@angular/forms';
import { Directive } from '@angular/core';
const userList = [
'jack',
'mary',
'jimi',
'tom'
];
@Directive({
selector:'[checkName]',
providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: CheckNameDirective, multi: true}]
})
export class CheckNameDirective implements AsyncValidator{
validate(control:AbstractControl) {
console.log(control);
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userList.indexOf(control.value) >= 0) {
resolve({
'checkName':control.value
});
} else {
resolve(null);
}
}, 2000)
});
}
}
在模板中使用
<input type="text" name="name" ngModel required #name="ngModel" checkName>
<div class="error" [style.color]="'red'" *ngIf="name.invalid && (name.dirty || name.touched || form.submitted)">
<p *ngIf="name.errors.required">name can not be empty!</p>
<p *ngIf="name.errors.checkName">this name is exist!</p>
</div>
几点说明:
- 异步验证器的本质也是一个属性型指令。
- 我们可以通过设置
providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: CheckNameDirective, multi: true}]
对NG_ASYNC_VALIDATORS
进行扩展。 - 该指令的类实现了
AsyncValidator
接口,需要实现validate
这个方法。validate
方法接收一个AbstractControl
类型的参数control
,我们可以通过control.value
获取到需要校验的值。与同步验证器不同的是,异步验证器的validate
方法返回一个Promise
对象,当延时操作执行完以后,resolve(null)
表示验证成功,resolve({'checkName':control.value})
表示验证失败,resolve
传递的数据会被附加到errors
对象中。 - 当所有的同步验证器验证通过后,才会开始异步验证。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。