1:在AppModule模块里面引入 ReactiveFormsModulecss
要使用响应式表单,就要从@angular/forms包中导入ReactiveFormsModule,并把它添加到你的NgModule的imports数组中。
import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ // other imports ... ReactiveFormsModule ], }) export class AppModule { }
2:建立一个新的组件html
ng g c NameEditor
3:请在组件中导入 FormControl 类数组
FormControl类是angular响应式表单最基本的构造快,要注册单个的表单控件,请在组件中导入FormControl类,并建立一个FormControl的新实例,把它保存在某个属性里面。
import { Component } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'app-name-editor', templateUrl: './name-editor.component.html', styleUrls: ['./name-editor.component.css'] }) export class NameEditorComponent { name = new FormControl(''); }
4:在组件的模板中注册一个表单控件app
修改模板,为表单控件添加 formControl 绑定,formControl 是由 ReactiveFormsModule 中的 FormControlDirective 提供的。
<label> Name: <input type="text" [formControl]="name"> </label> <p> Value: {{ name.value }} </p>
使用这种模板绑定语法,把该表单控件注册给了模板中名为 name 的输入元素。这样,表单控件和 DOM
元素就能够互相通信了:视图会反映模型的变化,模型也会反映视图中的变化。
5:替换表单控件的值异步
FormControl 提供了一个setValue()方法,他会修改这个表单控件的值。
js函数
updateName() { this.name.setValue('Nancy'); }
htmlui
<label> Name: <input type="text" [formControl]="name"> </label> <p> Value:{{name.value}} </p> <p> <button (click)="updateName()">Update Name</button> </p>
在这个例子中,你只使用单个控件FormControl,可是当调用 FormGroup 或 FormArray 的 setValue()
方法时,传入的值就必须匹配控件组或控件数组的结构才行6:把表单控件分组this
FormControl的实例能控制单个输入框所对应的控件,FormGroup能够控制一组FormControl实例的表单状态,当建立FormGroup时,其中的每个控件都会根据名字进行跟踪code
1>:建立新的组件component
ng g c ProfileEditor
2>:导入 FormGroup 和 FormControl 类而且建立 FormGroup实例
import { Component } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; @Component({ selector: 'app-profile-editor', templateUrl: './profile-editor.component.html', styleUrls: ['./profile-editor.component.css'] }) export class ProfileEditorComponent { profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), }); }
如今这些单独的控件FormControl被收集到了一个控件组中FormGroup, FormGroup 实例拥有和 FormControl 实例相同的属性(好比 value、untouched)和方法(好比 setValue())。3>:关联FormGroup的模型和视图
FormGroup能追踪每一个单独控件FormControl的状态和变化,若是其中某个控件的状态或值变化了,父控件也会一次新的状态变动或值变动事件
<form [formGroup]="profileForm"> <label> First Name: <input type="text" formControlName="firstName"> </label> <label> Last Name: <input type="text" formControlName="lastName"> </label> </form>
profileForm经过[formGroup]指令绑定到了 form
元素,在该模型和表单中的输入框之间建立了一个通信层,FormControlName 指令提供的 formControlName 属性把每一个输入框和 FormGroup 中定义的表单控件绑定起来。
4>:关联FormGroup的模型和视图
html
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()"> <label> First Name: </label> <input type="text" formControlName="firstName"> <label> Last Name: </label> <input type="text" formControlName="lastName"> <button type="submit" >Submit</button> </form>
js
onSubmit () { console.warn(this.profileForm.value); }
form 标签所发出的 submit 事件是原生 DOM 事件,经过点击类型为 submit 的按钮能够触发本事件
6:嵌套的表单组
js
profileForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), address: new FormGroup({ street: new FormControl(''), city: new FormControl(''), state: new FormControl(''), zip: new FormControl('') }) });
html
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()"> <label> First Name: </label> <input type="text" formControlName="firstName"> <label> Last Name: </label> <input type="text" formControlName="lastName"> <div formGroupName="address"> <label>Streel</label> <input type="text" formControlName="street"> <label>City</label> <input type="text" formControlName="city"> <label>State</label> <input type="text" formControlName="state"> <label>Zip Code</label> <input type="text" formControlName="zip"> </div> <button type="submit" [disabled]="!profileForm.valid">Submit</button> </form>
部分模型修改
html
<button (click)="updateProfile()">Update Profile</button>
js
updateProfile() { this.profileForm.patchValue({ firstName: 'Nancy', address: { street: '123 Drew Street' } }); }
patchValue() 方法要针对模型的结构进行更新。patchValue() 只会更新表单模型中所定义的那些属性。
6:使用 FormBuilder 来生成表单控件
FormBuilder 服务提供了一些便捷方法来生成表单控件。
FormBuilder在幕后也使用一样的方式来建立和返回这些实例,只是用起来更简单。 下面会重构 ProfileEditor 组件,用FormBuilder 来代替手工建立这些 FormControl 和 FormGroup。
Step 1 - 导入 FormBuilder 类
import { FormBuilder } from '@angular/forms';
Step 2 - 注入FormBuild 服务
constructor(private fb: FormBuilder) { }
Step 3- 生成表单控件
FormBuilder 服务有三个方法:control()、group() 和 array()。这些方法都是工厂方法,用于在组件类中分别生成
FormControl、FormGroup 和 FormArray。你可使用 group() 方法,用和前面同样的名字来定义这些属性。这里,每一个控件名对应的值都是一个数组,这个数组中的第一项是其初始值。你能够只使用初始值来定义控件,可是若是你的控件还须要同步或异步验证器,那就在这个数组中的第二项和第三项提供同步和异步验证器。
import { Component } from '@angular/core'; import { FormBuilder } from '@angular/forms'; @Component({ selector: 'app-profile-editor', templateUrl: './profile-editor.component.html', styleUrls: ['./profile-editor.component.css'] }) export class ProfileEditorComponent { profileForm = this.fb.group({ firstName: ['张'], lastName: ['娉'], address: this.fb.group({ street: [''], city: [''], state: [''], zip: [''] }), }); constructor(private fb: FormBuilder) { } }
7:简单的表单验证
如何把单个验证器添加到表单控件中,以及如何显示表单的总体状态。
Step 1 - 导入验证器函数
import { Validators } from '@angular/forms';
响应式表单包含了一组开箱即用的经常使用验证器函数。这些函数接收一个控件,用以验证并根据验证结果返回一个错误对象或空值。
Step 2 - 把字段设为必填
最多见的校验项是把一个字段设为必填项。本节描述如何为 firstName 控件添加“必填项”验证器。
在组件中,把静态方法 Validators.required 设置为 firstName 控件值数组中的第二项。
profileForm = this.fb.group({ firstName: ['', Validators.required], lastName: [''], address: this.fb.group({ street: [''], city: [''], state: [''], zip: [''] }), });
HTML5 有一组内置的属性,用来进行原生验证,包括 required、minlength、maxlength等。虽然是可选的,不过你也能够在表单的输入元素上把它们添加为附加属性来使用它们。这里咱们把 required 属性添加到 firstName
输入元素上。
<input type="text" formControlName="firstName" required>
这些 HTML5 验证器属性能够和 Angular
响应式表单提供的内置验证器组合使用。组合使用这两种验证器实践,能够防止在模板检查完以后表达式再次被修改致使的错误。
8:显示表单的状态
如今,你已经往表单控件上添加了一个必填字段,它的初始值是无效的(invalid)。这种无效状态冒泡到其父 FormGroup 中,也让这个 FormGroup 的状态变为无效的。你能够经过该 FormGroup 实例的 status 属性来访问其当前状态。
<p> Form Status: {{ profileForm.status }} </p>
9:使用表单数组管理动态控件
FormArray 是 FormGroup 以外的另外一个选择,用于管理任意数量的匿名控件,若是你事先不知道子控件的数量,FormArray是一个很好的选择
Step 1 - 导入 FormArray
import { FormArray } from '@angular/forms';
Step 2 - 定义 FormArray
为 profileForm 添加一个 aliases 属性,把它定义为 FormArray 类型。(FormBuilder 服务用于建立 FormArray 实例。)
profileForm = this.fb.group({ firstName: ['张', Validators.required], lastName: ['以'], address: this.fb.group({ street: [''], city: [''], state: [''], zip: [''] }), aliases: this.fb.array([ this.fb.control('') ]) });
Step 3 - 访问FormArray控件
经过 getter 来访问控件比较便捷,也容易复用
使用 getter 语法来建立一个名为 aliases 的类属性
get aliases() { }
从父控件 FormGroup 中接收绰号的 FormArray 控件。
get aliases() { return this.profileForm.get('aliases') as FormArray; } addAlias() { this.aliases.push(this.fb.control('')); }
Step 3 - 在模板中显示表单数组
在模型中定义了 aliases 的 FormArray 以后,你必须把它加入到模板中供用户输入,使用 formArrayName 在这个
FormArray 和模板之间创建绑定。
<div formArrayName="aliases"> <h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button> <div *ngFor="let address of aliases.controls; let i=index"> <!-- The repeated alias template --> <label> Alias: <input type="text" [formControlName]="i"> </label> </div> </div>
每当新的 alias 加进来时,FormArray 就会基于这个索引号提供它的控件。这将容许你在每次计算根控件的状态和值时跟踪每一个控件。
所有代码
html
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()"> <label> First Name: </label> <input type="text" formControlName="firstName" required> <label> Last Name: </label> <input type="text" formControlName="lastName"> <div formGroupName="address"> <h3>Address</h3> <label>Streel</label> <input type="text" formControlName="street"> <label>City</label> <input type="text" formControlName="city"> <label>State</label> <input type="text" formControlName="state"> <label>Zip Code</label> <input type="text" formControlName="zip"> </div> <div formArrayName="aliases"> <h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button> <div *ngFor="let address of aliases.controls; let i=index"> <label>Alias</label> <input type="text" [formControlName]="i" > </div> </div> <button type="submit" [disabled]="!profileForm.valid">Submit</button> <p> <button (click)="updateProfile()">Update Profile</button> </p> <p> Form Status: {{ profileForm.status }} </p> </form>
js
import { Component, OnInit } from '@angular/core'; import {FormControl, FormGroup, FormBuilder, Validators, FormArray} from '@angular/forms'; @Component({ selector: 'app-profile-editor', templateUrl: './profile-editor.component.html', styleUrls: ['./profile-editor.component.css'] }) export class ProfileEditorComponent implements OnInit { profileForm = this.fb.group({ firstName: ['张', Validators.required], lastName: ['以'], address: this.fb.group({ street: [''], city: [''], state: [''], zip: [''] }), aliases: this.fb.array([ this.fb.control('') ]) }); constructor(private fb: FormBuilder) { } ngOnInit() { } onSubmit () { console.warn(this.profileForm.value); } updateProfile() { this.profileForm.patchValue({ firstName: 'Nancy', address: { street: '123 Drew Street' } }); } get aliases () { return this.profileForm.get('aliases') as FormArray; } addAlias() { this.aliases.push(this.fb.control('')); } }