Angular 2 之五 表单
概述
标注方式定义表单步骤如下:
- 创建表单输入的数据模型
- 创建组件用于表单输入
- 创建组件模板用于表单布局
- 使用ngModel将数据模型字段双向绑定到对应的输入控件
- 输入控件增加ngControl属性
- 增加css视觉效果
- 显示或隐藏输入错误提示信息
- 表单数据验证正确之前禁用提交按钮
- 通过ngSubmit处理数据提交。
ngForm/ngControl标注方式
表单组件定义如下所示:
@Component({ selector: 'demo-form-sku', directives: [FORM_DIRECTIVES], template: ` <form #f="ngForm" (ngSubmit)="onSubmit(f.value)"> <div class="field"> <label for="skuInput">SKU</label> <input type="text" id="skuInput" placeholder="SKU" ngControl="sku"> </div> <button type="submit" class="ui button">Submit</button> </form> })
directives元数据注入FORM_DIRECTIVES,模板可使用ngForm directive。一般地,directive在匹配选择器(selector)后被加入元素,但Angular 2自动将ngForm加到模板的所有
元素中,并实现以下功能:
- 创建名为ngForm的ControlGroup,含ngFormModel属性除外
- 创建名为ngSubmit的事件绑定。
因此:
#f=“ngForm”
定义模板局部变量f,ngForm即自动创建的ControlGroup名(ngSubmit)=”onSubmit(f.value)”
中ngSubmit即自动创建的事件绑定,f.value即ControlGroup值,是一个控件名为key、输入值为value的JSON对象ngControl=”sku”
在ControlGroup中创建一个名为sku的Control,并将input元素和该Control关联,即input值和sku Control值关联- 注意示例仅用于输入,不包括双向数据绑定概念。
FormBuilder编程方式
上节通过ngForm和ngControl标注隐式创建ControlGroup和Control,虽然比较方便但是不够灵活,即无法定制各种选项。FormBuilder是一个工厂对象,用于编程创建ControlGroup和Control。
表单组件定义如下所示:
@Component({ selector: 'demo-form-sku-builder', directives: [FORM_DIRECTIVES], template: ` <form [ngFormModel]="myForm" (ngSubmit)="onSubmit(myForm.value)"> <div class="field"> <label for="skuInput">SKU</label> <input type="text" id="skuInput" placeholder="SKU" [ngFormControl]="myForm.controls['sku']"> </div> <button type="submit" class="ui button">Submit</button> </form>` })
export class DemoFormSkuBuilder { myForm: ControlGroup; constructor(fb: FormBuilder) { this.myForm = fb.group({ 'sku': ['ABC123'] }); } onSubmit(value: string): void { console.log('you submitted value: ', value); } }
和上节代码的区别在于:
- 组件构造函数注入FormBuilder对象,在构造函数中显式创建ControlGroup和名为sku的Contrrol对象
- ControlGroup局部变量名是
myForm
,模板使用ngFormModal属性指定该名称 - ngControl改为ngFormControl属性,表达式
myForm.controls[‘sku’]
的含义是从myForm ControlGroup的controls中获取名为sku的Control,并将input元素和该Control关联 - 同样示例仅用于输入,不包括双向数据绑定概念。
数据校验Validator
1. 内置数据校验
为确保用户输入正确的数据格式,Angular 2使用Validator校验输入数据,内置提供以下数据校验:
- MaxLengthValidator: 数据最大长度校验
- MinLengthValidator: 数据最小长度校验
- RequiredValidator: 必填字段校验
- PatternValidator: 正则表达式模板校验
2. 5.5.2 使用数据校验
创建Control时指明数据验证条件,如:
this.myForm = fb.group({
'sku': ['', Validators.required]
});
如果是多个条件则采用组合方式(skuValidator是自定义的),如:
this.myForm = fb.group({
'sku': ['', Validators.compose([
Validators.required, skuValidator])]
});
3. 错误信息提示
Angular 2使用Control的CSS class反映状态:
- 是否已访问:ng-touched和ng-untouched
- 值是否改变:ng-dirty和ng-pristine
-
值是否有效:ng-valid和ng-invalid 可以通过CSS类显示字段级的错误信息,如:
<div *ngIf="!sku.control.valid" class="ui error message"> SKU is invalid </div>
如果该字段有多个数据校验条件,则可使用:
<div *ngIf="sku.control.hasError('required')" class="ui error message"> SKU is required </div>
4. 自定义数据校验
自定义数据校验如下所示:
export class Validators { static required(c: Control): StringMap<string, boolean> { return isBlank(c.value) || c.value == "" ? {"required": true} : null; }
其中:
- 函数名即Validator名称
- 输入是Control对象
- 输出是
StringMap<string, boolean>
,其中key是错误名称(error code),value等于true表示格式有误。
返回Promise<ValidationResult>
可实现异步数据校验。
双向数据绑定
ngModel用于模型和表单的双向数据绑定,例如:
<input type="text" id="productNameInput" placeholder="Product Name" [ngFormControl]="myForm.find('productName')" [(ngModel)]="productName">
这里使用ngFormControl是为了实现数据校验功能。
提交数据
点type=”submit”的按钮将触发ngSubmit事件。当表单数据不正确时可禁用该按钮,如:
<button type="submit" class="btn btn-default [disabled]="!heroForm.form.valid"> Submit </button>
在onSubmit()回调函数中,可获取ControlGroup值对象,其中key是控件名称,value是输入值。
输入数据变化
ControlGroup和Control的valueChanges方法返回Observable对象。subscribe 该返回对象可以获取输入值变化的异步数据流。