详解Angular2响应式表单(2)

对上文的总结就是,相比ng1中数据的双向绑定,ng2保留了这个双向绑定能力(底层其实优化了很多),原先的ng-model指令升级成了ngModel,使用的功能保持不变。

同时尽管ng2版本的数据双向绑定得到了很大的优化,仍改变不了其数据异步绑定的方式,因为ng2不能确定数据何时绑定,我们也不能确定很多网络请求得到的数据到来的时间。

在ng1中其实这个机制会有一些尴尬的场景,至少笔者在一些情况下不得不在一些业务场景下使用setTimeout来保证数据已经成功绑定进入scope的watch循环,但这个异步绑定数据又是不可避免的,除非我们自己来适应实际项目改写angular代码了。

所以ng2就提供了让我们配合具体项目场景改写ngModel的能力,也就是原文介绍的响应式表单。

其跟ngModel的关系就是,ngModel是响应式表单的官方实现,其在我们绑定数据时自动为我们实现响应式表单中用到的几个机制,如果我们需要数据严格的实时同步绑定,就不必使用ngModel,可以亲自来编写响应式的表单,步骤覆盖了组件模板到数据模型类整条龙,而这么多事情在合适的场景下使用ngModel已经可以实现了,这两种表单绑定的方式各有其优势。

 1. 使用响应式表单

响应式表单的能力封装在ReactiveFormsModule中,并且跟FormsModule同时包含在@angular/forms这个包中。

表单类的要点:

1.AbstractControl是FormControl、FormGroup、FormArray这三个实例表单类的抽象基类。它提供了他们的通用行为以及属性,其中就有observable。

2.FormControl在单个表单控件中检查值并验证状态。它负责将其通知给HTML表单控件(比如input这些)。

3.FormGroup负责AbstractControl实例的一个组的值与验证状态。组的属性包含了它们的子控件。你的组件的顶级表单就是一个FormGroup。

4.FormArray负责AbstractControl实例的数值索引数组的值与状态验证。

2. FormControl

最核心的指令就是FormControl,算是底层的ngModel,在模板标签中跟定义好的数据模型字段绑定起来,就像这样:

<h2>Hero Detail</h2> <h3><i>Just a FormControl</i></h3> <label>Name: <input [formControl]="name"> </label>

同时在组件代码中需要将上例中这个name字段声明为FormControl类:

export class HeroDetailComponent1 { name = new FormControl(); }

3. FormGroup

将多个FormControl对象分组到FormGroup中,用来方便管理。定义方法如下:

import { Component } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; export class HeroDetailComponent2 { heroForm = new FormGroup ({ name: new FormControl() }); }

此时模板标签中也要分组来写:

<h2>Hero Detail</h2> <h3><i>FormControl in a FormGroup</i></h3> <form [formGroup]="heroForm" novalidate> <div> <label>Name: <input formControlName="name"> </label> </div> </form>

现在的效果就是可以从heroForm中实时读取到其值和一些附加的状态的变化。

可以在模板中添加两个标签来展示数据的更改:

<p>Form value: {{ heroForm.value | json }}</p> <p>Form status: {{ heroForm.status | json }}</p>

4. FormBuilder

还有个新概念就是FormBuilder,是用来帮助创建表单类的:

1. 显示声明heroForm属性的类型为FormGroup,后面你将会初始化它

2. 注入FormBuilder到构造器中

3. 使用FormsBuilder添加新方法定义heroForm,叫做createForm。

4. 在构造器中执行createForm方法。

export class HeroDetailComponent3 { heroForm: FormGroup; // <--- heroForm is of type FormGroup constructor(private fb: FormBuilder) { // <--- inject FormBuilder this.createForm(); } createForm() { this.heroForm = this.fb.group({ name: '', // <--- the FormControl called "name" }); } }

上例中执行createForm方法即可动态快速的创建出表单类,其在一些表单类需要更改的场景下可以使用。

5. setValue和patchValue

这两个方法是真正给表单模型赋值用的。因为表单显示的数据与真实的底层数据肯定不能使同一个,否则表单输入数据一旦更改,源数据就被污染了,而这两个方法就是用来将源数据赋值到表单模型数据上的。

每当需要赋值时就可以调用,其中setValue必须准确赋值,并且会在数据不匹配时报告错误;而patchValue没有这么严格,但可以传一个对象,且不匹配时不会报告错误。

而我们要做的就是在ng2组件的ngOnChanges回调中手动执行setValue设置数据值。比如这样:

ngOnChanges() this.heroForm.setValue({ name: this.hero.name, address: this.hero.addresses[0] || new Address() }); }

同时ng2还提供了一个reset方法来重新调用setValue方法(setValue本身好像只是用来一次性赋值的)。

6. FormArray

FormArray是用来对付FormGroups列表的,比如一个英雄有可能有多个address字段,address字段本身就是个FormGroup,此时就要用到FormArray了:

this.heroForm = this.fb.group({ name: ['', Validators.required ], secretLairs: this.fb.array([]), // <-- secretLairs as an empty FormArray power: '', sidekick: '' });

获取FormArray要用到FormGroup提供的一个get方法:

get secretLairs(): FormArray { return this.heroForm.get('secretLairs') as FormArray; };

其显示的模板如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyxzjy.html