1:在AppModule模組裡面引入 ReactiveFormsModule
要使用響應式表單,就要從@angular/forms包中匯入ReactiveFormsModule,並把它新增到你的NgModule的imports陣列中。
import { ReactiveFormsModule } from `@angular/forms`;
@NgModule({
imports: [
// other imports ...
ReactiveFormsModule
],
})
export class AppModule { }
2:建立一個新的元件
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:在元件的模板中註冊一個表單控制元件
修改模板,為表單控制元件新增 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`);
}
html
<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:把表單控制元件分組
FormControl的例項能控制單個輸入框所對應的控制元件,FormGroup可以控制一組FormControl例項的表單狀態,當建立FormGroup時,其中的每一個控制元件都會根據名字進行跟蹤
1>:建立新的元件
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(``));
}
}