Angular 響應(yīng)式表單

2022-07-06 09:51 更新

響應(yīng)式表單

響應(yīng)式表單提供了一種模型驅(qū)動的方式來處理表單輸入,其中的值會隨時(shí)間而變化。本文會向你展示如何創(chuàng)建和更新基本的表單控件,接下來還會在一個(gè)表單組中使用多個(gè)控件,驗(yàn)證表單的值,以及創(chuàng)建動態(tài)表單,也就是在運(yùn)行期添加或移除控件。

試試這個(gè)響應(yīng)式表單的現(xiàn)場演練 / 下載范例。

響應(yīng)式表單概述

響應(yīng)式表單使用顯式的、不可變的方式,管理表單在特定的時(shí)間點(diǎn)上的狀態(tài)。對表單狀態(tài)的每一次變更都會返回一個(gè)新的狀態(tài),這樣可以在變化時(shí)維護(hù)模型的整體性。響應(yīng)式表單是圍繞 ?Observable ?流構(gòu)建的,表單的輸入和值都是通過這些輸入值組成的流來提供的,它可以同步訪問。

響應(yīng)式表單還提供了一種更直觀的測試路徑,因?yàn)樵谡埱髸r(shí)你可以確信這些數(shù)據(jù)是一致的、可預(yù)料的。這個(gè)流的任何一個(gè)消費(fèi)者都可以安全地操縱這些數(shù)據(jù)。

響應(yīng)式表單與模板驅(qū)動表單有著顯著的不同點(diǎn)。響應(yīng)式表單通過對數(shù)據(jù)模型的同步訪問提供了更多的可預(yù)測性,使用 Observable 的操作符提供了不可變性,并且通過 Observable 流提供了變化追蹤功能。

模板驅(qū)動表單允許你直接在模板中修改數(shù)據(jù),但不像響應(yīng)式表單那么明確,因?yàn)樗鼈円蕾嚽度氲侥0逯械闹噶?,并借助可變?shù)據(jù)來異步跟蹤變化。

添加基礎(chǔ)表單控件

使用表單控件有三個(gè)步驟。

  1. 在你的應(yīng)用中注冊響應(yīng)式表單模塊。該模塊聲明了一些你要用在響應(yīng)式表單中的指令。
  2. 生成一個(gè)新的 ?FormControl ?實(shí)例,并把它保存在組件中。
  3. 在模板中注冊這個(gè) ?FormControl?。

然后,你可以把組件添加到模板中來顯示表單。

下面的例子展示了如何添加一個(gè)表單控件。在這個(gè)例子中,用戶在輸入字段中輸入自己的名字,捕獲其輸入值,并顯示表單控件的當(dāng)前值。

動作

詳情

注冊響應(yīng)式表單模塊

要使用響應(yīng)式表單控件,就要從 @angular/forms 包中導(dǎo)入 ReactiveFormsModule,并把它添加到你的 NgModule 的 imports 數(shù)組中。

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    // other imports ...
    ReactiveFormsModule
  ],
})
export class AppModule { }

生成新的 FormControl

使用 CLI 命令 ng generate 在項(xiàng)目中生成一個(gè)組件作為該表單控件的宿主。

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('');
}

可以用 ?FormControl ?的構(gòu)造函數(shù)設(shè)置初始值,這個(gè)例子中它是空字符串。通過在你的組件類中創(chuàng)建這些控件,你可以直接對表單控件的狀態(tài)進(jìn)行監(jiān)聽、修改和校驗(yàn)。

在模板中注冊該控件

在組件類中創(chuàng)建了控件之后,你還要把它和模板中的一個(gè)表單控件關(guān)聯(lián)起來。修改模板,為表單控件添加 ?formControl ?綁定,?formControl ?是由 ?ReactiveFormsModule ?中的 ?FormControlDirective ?提供的。
<label for="name">Name: </label>
<input id="name" type="text" [formControl]="name">
使用這種模板綁定語法,把該表單控件注冊給了模板中名為 ?name ?的輸入元素。這樣,表單控件和 DOM 元素就可以互相通訊了:視圖會反映模型的變化,模型也會反映視圖中的變化。

顯示該組件

把該組件添加到模板時(shí),將顯示指派給 ?name ?的表單控件。

<app-name-editor></app-name-editor>

顯示表單控件的值

你可以用下列方式顯示它的值。

  • 通過可觀察對象 ?valueChanges?,你可以在模板中使用 ?AsyncPipe ?或在組件類中使用 ?subscribe()? 方法來監(jiān)聽表單值的變化。
  • 使用 ?value ?屬性。它能讓你獲得當(dāng)前值的一份快照。

下面的例子展示了如何在模板中使用插值顯示當(dāng)前值。

<p>Value: {{ name.value }}</p>

一旦你修改了表單控件所關(guān)聯(lián)的元素,這里顯示的值也跟著變化了。

響應(yīng)式表單還能通過每個(gè)實(shí)例的屬性和方法提供關(guān)于特定控件的更多信息。?AbstractControl ?的這些屬性和方法用于控制表單狀態(tài),并在處理表單校驗(yàn)時(shí)決定何時(shí)顯示信息。

替換表單控件的值

響應(yīng)式表單還有一些方法可以用編程的方式修改控件的值,它讓你可以靈活的修改控件的值而不需要借助用戶交互。?FormControl ?提供了一個(gè) ?setValue()? 方法,它會修改這個(gè)表單控件的值,并且驗(yàn)證與控件結(jié)構(gòu)相對應(yīng)的值的結(jié)構(gòu)。比如,當(dāng)從后端 API 或服務(wù)接收到了表單數(shù)據(jù)時(shí),可以通過 ?setValue()? 方法來把原來的值替換為新的值。

下列的例子往組件類中添加了一個(gè)方法,它使用 ?setValue()? 方法來修改 Nancy 控件的值。

updateName() {
  this.name.setValue('Nancy');
}

修改模板,添加一個(gè)按鈕,用于模擬改名操作。在點(diǎn) ?Update Name? 按鈕之前表單控件元素中輸入的任何值都會回顯為它的當(dāng)前值。

<button type="button" (click)="updateName()">Update Name</button>

由于表單模型是該控件的事實(shí)之源,因此當(dāng)你單擊該按鈕時(shí),組件中該輸入框的值也變化了,覆蓋掉它的當(dāng)前值。


注意:
在這個(gè)例子中,你只使用單個(gè)控件,但是當(dāng)調(diào)用 ?FormGroup ?或 ?FormArray ?實(shí)例的 ?setValue()? 方法時(shí),傳入的值就必須匹配控件組或控件數(shù)組的結(jié)構(gòu)才行。

把表單控件分組

表單中通常會包含幾個(gè)相互關(guān)聯(lián)的控件。響應(yīng)式表單提供了兩種把多個(gè)相關(guān)控件分組到同一個(gè)輸入表單中的方法。

表單組

詳情

表單分組

定義了一個(gè)帶有一組控件的表單,你可以把它們放在一起管理。表單組的基礎(chǔ)知識將在本節(jié)中討論。你也可以通過嵌套表單組來創(chuàng)建更復(fù)雜的表單。

表單數(shù)組

定義了一個(gè)動態(tài)表單,你可以在運(yùn)行時(shí)添加和刪除控件。你也可以通過嵌套表單數(shù)組來創(chuàng)建更復(fù)雜的表單。

就像 ?FormControl ?的實(shí)例能讓你控制單個(gè)輸入框所對應(yīng)的控件一樣,?FormGroup ?的實(shí)例也能跟蹤一組 ?FormControl ?實(shí)例(比如一個(gè)表單)的表單狀態(tài)。當(dāng)創(chuàng)建 ?FormGroup ?時(shí),其中的每個(gè)控件都會根據(jù)其名字進(jìn)行跟蹤。下面的例子展示了如何管理單個(gè)控件組中的多個(gè) ?FormControl ?實(shí)例。

生成一個(gè) ?ProfileEditor ?組件并從 ?@angular/forms? 包中導(dǎo)入 ?FormGroup ?和 ?FormControl ?類。

ng generate component ProfileEditor
import { FormGroup, FormControl } from '@angular/forms';

要將表單組添加到此組件中,請執(zhí)行以下步驟。

  1. 創(chuàng)建一個(gè) ?FormGroup ?實(shí)例。
  2. 把這個(gè) ?FormGroup ?模型關(guān)聯(lián)到視圖。
  3. 保存表單數(shù)據(jù)。

動作

詳情

創(chuàng)建一個(gè) FormGroup 實(shí)例。

在組件類中創(chuàng)建一個(gè)名叫 ?profileForm ?的屬性,并設(shè)置為 ?FormGroup ?的一個(gè)新實(shí)例。要初始化這個(gè) ?FormGroup?,請為構(gòu)造函數(shù)提供一個(gè)由控件組成的對象,對象中的每個(gè)名字都要和表單控件的名字一一對應(yīng)。

對此個(gè)人檔案表單,要添加兩個(gè) ?FormControl ?實(shí)例,名字分別為 ?firstName ?和 ?lastName?。

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(''),
  });
}

這些獨(dú)立的表單控件被收集到了一個(gè)控件組中。這個(gè) ?FormGroup ?用對象的形式提供了它的模型值,這個(gè)值來自組中每個(gè)控件的值。?FormGroup ?實(shí)例擁有和 ?FormControl ?實(shí)例相同的屬性(比如 ?value?、?untouched?)和方法(比如 ?setValue()?)。

把這個(gè) FormGroup 模型關(guān)聯(lián)到視圖。

這個(gè)表單組還能跟蹤其中每個(gè)控件的狀態(tài)及其變化,所以如果其中的某個(gè)控件的狀態(tài)或值變化了,父控件也會發(fā)出一次新的狀態(tài)變更或值變更事件。該控件組的模型來自它的所有成員。在定義了這個(gè)模型之后,你必須更新模板,來把該模型反映到視圖中。

<form [formGroup]="profileForm">

  <label for="first-name">First Name: </label>
  <input id="first-name" type="text" formControlName="firstName">

  <label for="last-name">Last Name: </label>
  <input id="last-name" type="text" formControlName="lastName">

</form>
NOTE:
就像 ?FormGroup ?所包含的那控件一樣,profileForm 這個(gè) ?FormGroup ?也通過 ?FormGroup ?指令綁定到了 ?form ?元素,在該模型和表單中的輸入框之間創(chuàng)建了一個(gè)通訊層。

由 ?FormControlName ?指令提供的 ?formControlName ?屬性把每個(gè)輸入框和 ?FormGroup ?中定義的表單控件綁定起來。這些表單控件會和相應(yīng)的元素通訊,它們還把更改傳給 ?FormGroup?,這個(gè) ?FormGroup ?是模型值的事實(shí)之源。

保存表單數(shù)據(jù)

?ProfileEditor ?組件從用戶那里獲得輸入,但在真實(shí)的場景中,你可能想要先捕獲表單的值,等將來在組件外部進(jìn)行處理。?FormGroup ?指令會監(jiān)聽 ?form ?元素發(fā)出的 ?submit ?事件,并發(fā)出一個(gè) ?ngSubmit ?事件,讓你可以綁定一個(gè)回調(diào)函數(shù)。把 ?onSubmit()? 回調(diào)方法添加為 ?form ?標(biāo)簽上的 ?ngSubmit ?事件監(jiān)聽器。

<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">

?ProfileEditor ?組件上的 ?onSubmit()? 方法會捕獲 ?profileForm ?的當(dāng)前值。要保持該表單的封裝性,就要使用 ?EventEmitter ?向組件外部提供該表單的值。下面的例子會使用 ?console.warn? 把這個(gè)值記錄到瀏覽器的控制臺中。

onSubmit() {
  // TODO: Use EventEmitter with form value
  console.warn(this.profileForm.value);
}

?form ?標(biāo)簽所發(fā)出的 ?submit ?事件是內(nèi)置 DOM 事件,通過點(diǎn)擊類型為 ?submit ?的按鈕可以觸發(fā)本事件。這還讓用戶可以用回車鍵來提交填完的表單。往表單的底部添加一個(gè) ?button?,用于觸發(fā)表單提交。

<p>Complete the form to enable button.</p>
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
注意:
上面這個(gè)代碼片段中的按鈕還附加了一個(gè) ?disabled ?綁定,用于在 ?profileForm ?無效時(shí)禁用該按鈕。目前你還沒有執(zhí)行任何表單驗(yàn)證邏輯,因此該按鈕始終是可用的。

顯示此組件

要顯示包含此表單的 ?ProfileEditor ?組件,請把它添加到組件模板中。

<app-profile-editor></app-profile-editor>

?ProfileEditor ?讓你能管理 ?FormGroup ?中的 ?firstName ?和 ?lastName ?等 ?FormControl ?實(shí)例。



創(chuàng)建嵌套的表單組

表單組可以同時(shí)接受單個(gè)表單控件實(shí)例和其它表單組實(shí)例作為其子控件。這可以讓復(fù)雜的表單模型更容易維護(hù),并在邏輯上把它們分組到一起。

如果要構(gòu)建復(fù)雜的表單,如果能在更小的分區(qū)中管理不同類別的信息就會更容易一些。使用嵌套的 ?FormGroup ?可以讓你把大型表單組織成一些稍小的、易管理的分組。

要制作更復(fù)雜的表單,請遵循如下步驟。

  1. 創(chuàng)建一個(gè)嵌套的表單組。
  2. 在模板中對這個(gè)嵌套表單分組。

某些類型的信息天然就屬于同一個(gè)組。比如名稱和地址就是這類嵌套組的典型例子,下面的例子中就用到了它們。

動作

詳情

創(chuàng)建一個(gè)嵌套的表單組。

要在 profileForm 中創(chuàng)建一個(gè)嵌套組,就要把一個(gè)嵌套的 address 元素添加到此表單組的實(shí)例中。

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(''),
    address: new FormGroup({
      street: new FormControl(''),
      city: new FormControl(''),
      state: new FormControl(''),
      zip: new FormControl('')
    })
  });
}

在這個(gè)例子中,?address group? 把現(xiàn)有的 ?firstName?、?lastName ?控件和新的 ?street?、?city?、?state ?和 ?zip ?控件組合在一起。雖然 ?address ?這個(gè) ?FormGroup ?是 ?profileForm ?這個(gè)整體 ?FormGroup ?的一個(gè)子控件,但是仍然適用同樣的值和狀態(tài)的變更規(guī)則。來自內(nèi)嵌控件組的狀態(tài)和值的變更將會冒泡到它的父控件組,以維護(hù)整體模型的一致性。

在模板中對這個(gè)嵌套表單分組。

在修改了組件類中的模型之后,還要修改模板,來把這個(gè) FormGroup 實(shí)例對接到它的輸入元素。
<div formGroupName="address">
  <h2>Address</h2>

  <label for="street">Street: </label>
  <input id="street" type="text" formControlName="street">

  <label for="city">City: </label>
  <input id="city" type="text" formControlName="city">

  <label for="state">State: </label>
  <input id="state" type="text" formControlName="state">

  <label for="zip">Zip Code: </label>
  <input id="zip" type="text" formControlName="zip">
</div>
?ProfileEditor ?表單顯示為一個(gè)組,但是將來這個(gè)模型會被進(jìn)一步細(xì)分,以表示邏輯分組區(qū)域。
提示:
這里使用了 ?value ?屬性和 ?JsonPipe ?管道在組件模板中顯示了這個(gè) ?FormGroup ?的值。

更新部分?jǐn)?shù)據(jù)模型

當(dāng)修改包含多個(gè) ?FormGroup ?實(shí)例的值時(shí),你可能只希望更新模型中的一部分,而不是完全替換掉。這一節(jié)會講解該如何更新 ?AbstractControl ?模型中的一部分。

有兩種更新模型值的方式:

方法

詳情

setValue()

使用 setValue() 方法來為單個(gè)控件設(shè)置新值。setValue() 方法會嚴(yán)格遵循表單組的結(jié)構(gòu),并整體性替換控件的值。

patchValue()

使用 patchValue() 方法可以用對象中所定義的任何屬性為表單模型進(jìn)行替換。

?setValue()? 方法的嚴(yán)格檢查可以幫助你捕獲復(fù)雜表單嵌套中的錯誤,而 ?patchValue()? 在遇到那些錯誤時(shí)可能會默默的失敗。

在 ?ProfileEditorComponent ?中,使用 ?updateProfile ?方法傳入下列數(shù)據(jù)可以更新用戶的名字與街道住址。

updateProfile() {
  this.profileForm.patchValue({
    firstName: 'Nancy',
    address: {
      street: '123 Drew Street'
    }
  });
}

通過往模板中添加一個(gè)按鈕來模擬一次更新操作,以修改用戶檔案。

<button type="button" (click)="updateProfile()">Update Profile</button>

當(dāng)點(diǎn)擊按鈕時(shí),?profileForm ?模型中只有 ?firstName ?和 ?street ?被修改了。注意,?street ?是在 ?address ?屬性的對象中被修改的。這種結(jié)構(gòu)是必須的,因?yàn)?nbsp;?patchValue()? 方法要針對模型的結(jié)構(gòu)進(jìn)行更新。?patchValue()? 只會更新表單模型中所定義的那些屬性。

使用 FormBuilder 服務(wù)生成控件

當(dāng)需要與多個(gè)表單打交道時(shí),手動創(chuàng)建多個(gè)表單控件實(shí)例會非常繁瑣。?FormBuilder ?服務(wù)提供了一些便捷方法來生成表單控件。?FormBuilder ?在幕后也使用同樣的方式來創(chuàng)建和返回這些實(shí)例,只是用起來更簡單。

通過下列步驟可以利用這項(xiàng)服務(wù)。

  1. 導(dǎo)入 ?FormBuilder ?類。
  2. 注入這個(gè) ?FormBuilder ?服務(wù)。
  3. 生成表單內(nèi)容。

下面的例子展示了如何重構(gòu) ?ProfileEditor ?組件,用 ?FormBuilder ?來代替手工創(chuàng)建這些 ?FormControl ?和 ?FormGroup ?實(shí)例。

動作

詳情

導(dǎo)入 FormBuilder 類

從 ?@angular/forms? 包中導(dǎo)入 ?FormBuilder ?類。
import { FormBuilder } from '@angular/forms';

注入 FormBuilder 服務(wù)

?FormBuilder ?是一個(gè)可注入的服務(wù)提供者,它是由 ?ReactiveFormModule ?提供的。只要把它添加到組件的構(gòu)造函數(shù)中就可以注入這個(gè)依賴。

constructor(private fb: FormBuilder) { }

生成表單控件

?FormBuilder ?服務(wù)有三個(gè)方法:?control()?、?group()? 和 ?array()?。這些方法都是工廠方法,用于在組件類中分別生成 ?FormControl?、?FormGroup ?和 ?FormArray?。

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) { }
}

在上面的例子中,你可以使用 ?group()? 方法,用和前面一樣的名字來定義這些屬性。這里,每個(gè)控件名對應(yīng)的值都是一個(gè)數(shù)組,這個(gè)數(shù)組中的第一項(xiàng)是其初始值。

提示:
你可以只使用初始值來定義控件,但是如果你的控件還需要同步或異步驗(yàn)證器,那就在這個(gè)數(shù)組中的第二項(xiàng)和第三項(xiàng)提供同步和異步驗(yàn)證器。

比較一下用表單構(gòu)建器和手動創(chuàng)建實(shí)例這兩種方式。

  • src/app/profile-editor/profile-editor.component.ts (instances)
  • profileForm = new FormGroup({
      firstName: new FormControl(''),
      lastName: new FormControl(''),
      address: new FormGroup({
        street: new FormControl(''),
        city: new FormControl(''),
        state: new FormControl(''),
        zip: new FormControl('')
      })
    });
  • src/app/profile-editor/profile-editor.component.ts (form builder)
    profileForm = this.fb.group({
      firstName: [''],
      lastName: [''],
      address: this.fb.group({
        street: [''],
        city: [''],
        state: [''],
        zip: ['']
      }),
    });

驗(yàn)證表單輸入

表單驗(yàn)證用于確保用戶的輸入是完整和正確的。本節(jié)講解了如何把單個(gè)驗(yàn)證器添加到表單控件中,以及如何顯示表單的整體狀態(tài)。

使用下列步驟添加表單驗(yàn)證。

  1. 在表單組件中導(dǎo)入一個(gè)驗(yàn)證器函數(shù)。
  2. 把這個(gè)驗(yàn)證器添加到表單中的相應(yīng)字段。
  3. 添加邏輯來處理驗(yàn)證狀態(tài)。

最常見的驗(yàn)證是做一個(gè)必填字段。下面的例子給出了如何在 ?firstName ?控件中添加必填驗(yàn)證并顯示驗(yàn)證結(jié)果的方法。

操作

詳情

導(dǎo)入驗(yàn)證器函數(shù)

響應(yīng)式表單包含了一組開箱即用的常用驗(yàn)證器函數(shù)。這些函數(shù)接收一個(gè)控件,用以驗(yàn)證并根據(jù)驗(yàn)證結(jié)果返回一個(gè)錯誤對象或空值。

從 ?@angular/forms? 包中導(dǎo)入 ?Validators ?類。

import { Validators } from '@angular/forms';

建一個(gè)必填字段

在 ?ProfileEditor ?組件中,把靜態(tài)方法 ?Validators.required? 設(shè)置為 ?firstName ?控件值數(shù)組中的第二項(xiàng)。

profileForm = this.fb.group({
  firstName: ['', Validators.required],
  lastName: [''],
  address: this.fb.group({
    street: [''],
    city: [''],
    state: [''],
    zip: ['']
  }),
});

顯示表單狀態(tài)

當(dāng)你往表單控件上添加了一個(gè)必填字段時(shí),它的初始值是無效的(invalid)。這種無效狀態(tài)會傳播到其父 ?FormGroup ?元素中,也讓這個(gè) ?FormGroup ?的狀態(tài)變?yōu)闊o效的。你可以通過該 ?FormGroup ?實(shí)例的 ?status ?屬性來訪問其當(dāng)前狀態(tài)。
<p>Form Status: {{ profileForm.status }}</p>

提交按鈕被禁用了,因?yàn)??firstName ?控件的必填項(xiàng)規(guī)則導(dǎo)致了 ?profileForm ?也是無效的。在你填寫了 ?firstName ?輸入框之后,該表單就變成了有效的,并且提交按鈕也啟用了。

創(chuàng)建動態(tài)表單

?FormArray ?是 ?FormGroup ?之外的另一個(gè)選擇,用于管理任意數(shù)量的匿名控件。像 ?FormGroup ?實(shí)例一樣,你也可以往 ?FormArray ?中動態(tài)插入和移除控件,并且 ?FormArray ?實(shí)例的值和驗(yàn)證狀態(tài)也是根據(jù)它的子控件計(jì)算得來的。不過,你不需要為每個(gè)控件定義一個(gè)名字作為 key,因此,如果你事先不知道子控件的數(shù)量,這就是一個(gè)很好的選擇。

要定義一個(gè)動態(tài)表單,請執(zhí)行以下步驟。

  1. 導(dǎo)入 ?FormArray ?類。
  2. 定義一個(gè) ?FormArray ?控件。
  3. 使用 getter 方法訪問 ?FormArray ?控件。
  4. 在模板中顯示這個(gè)表單數(shù)組。

下面的例子展示了如何在 ?ProfileEditor ?中管理別名數(shù)組。

操作

詳情

導(dǎo)入 ??FormArray?? 類

從 ?@angular/form? 中導(dǎo)入 ?FormArray?,以使用它的類型信息。?FormBuilder ?服務(wù)用于創(chuàng)建 ?FormArray ?實(shí)例。

import { FormArray } from '@angular/forms';

定義 FormArray 控件

你可以通過把一組(從零項(xiàng)到多項(xiàng))控件定義在一個(gè)數(shù)組中來初始化一個(gè) ?FormArray?。為 ?profileForm ?添加一個(gè) ?aliases ?屬性,把它定義為 ?FormArray ?類型。

使用 ?FormBuilder.array()? 方法來定義該數(shù)組,并用 ?FormBuilder.control()? 方法來往該數(shù)組中添加一個(gè)初始控件。

profileForm = this.fb.group({
  firstName: ['', Validators.required],
  lastName: [''],
  address: this.fb.group({
    street: [''],
    city: [''],
    state: [''],
    zip: ['']
  }),
  aliases: this.fb.array([
    this.fb.control('')
  ])
});

FormGroup ?中的這個(gè) ?aliases ?控件現(xiàn)在管理著一個(gè)控件,將來還可以動態(tài)添加多個(gè)。

訪問 FormArray 控件

相對于重復(fù)使用 ?profileForm.get()? 方法獲取每個(gè)實(shí)例的方式,getter 可以讓你輕松訪問表單數(shù)組各個(gè)實(shí)例中的別名。表單數(shù)組實(shí)例用一個(gè)數(shù)組來代表未定數(shù)量的控件。通過 getter 來訪問控件很方便,這種方法還能很容易地重復(fù)處理更多控件。
使用 getter 語法創(chuàng)建類屬性 ?aliases?,以從父表單組中接收表示綽號的表單數(shù)組控件。
get aliases() {
  return this.profileForm.get('aliases') as FormArray;
}
注意:
因?yàn)榉祷氐目丶念愋褪?nbsp;?AbstractControl?,所以你要為該方法提供一個(gè)顯式的類型聲明來訪問 ?FormArray ?特有的語法。
定義一個(gè)方法來把一個(gè)綽號控件動態(tài)插入到綽號 ?FormArray ?中。用 ?FormArray.push()? 方法把該控件添加為數(shù)組中的新條目。
addAlias() {
  this.aliases.push(this.fb.control(''));
}
在這個(gè)模板中,這些控件會被迭代,把每個(gè)控件都顯示為一個(gè)獨(dú)立的輸入框。

在模板中顯示表單數(shù)組

要想為表單模型添加 ?aliases?,你必須把它加入到模板中供用戶輸入。和 ?FormGroupNameDirective ?提供的 ?formGroupName ?一樣,?FormArrayNameDirective ?也使用 ?formArrayName ?在這個(gè) ?FormArray ?實(shí)例和模板之間建立綁定。
在 ?formGroupName ??<div>? 元素的結(jié)束標(biāo)簽下方,添加一段模板 HTML。
<div formArrayName="aliases">
  <h2>Aliases</h2>
  <button type="button" (click)="addAlias()">+ Add another alias</button>

  <div *ngFor="let alias of aliases.controls; let i=index">
    <!-- The repeated alias template -->
    <label for="alias-{{ i }}">Alias:</label>
    <input id="alias-{{ i }}" type="text" [formControlName]="i">
  </div>
</div>
?*ngFor? 指令對 ?aliases ??FormArray ?提供的每個(gè) ?FormControl ?進(jìn)行迭代。因?yàn)??FormArray ?中的元素是匿名的,所以你要把索引號賦值給 ?i? 變量,并且把它傳給每個(gè)控件的 ?formControlName ?輸入屬性。

每當(dāng)新的 ?alias ?加進(jìn)來時(shí),?FormArray ?的實(shí)例就會基于這個(gè)索引號提供它的控件。這將允許你在每次計(jì)算根控件的狀態(tài)和值時(shí)跟蹤每個(gè)控件。

添加一個(gè)別名

最初,表單只包含一個(gè)綽號字段,點(diǎn)擊 ?Add Alias? 按鈕,就出現(xiàn)了另一個(gè)字段。你還可以驗(yàn)證由模板底部的“Form Value”顯示出來的表單模型所報(bào)告的這個(gè)綽號數(shù)組。

注意:
除了為每個(gè)綽號使用 ?FormControl ?之外,你還可以改用 ?FormGroup ?來組合上一些額外字段。對其中的每個(gè)條目定義控件的過程和前面沒有區(qū)別。

響應(yīng)式表單 API 匯總

下表給出了用于創(chuàng)建和管理響應(yīng)式表單控件的基礎(chǔ)類和服務(wù)。

詳情

AbstractControl

所有三種表單控件類(FormControl、FormGroup 和 FormArray)的抽象基類。它提供了一些公共的行為和屬性。

FormControl

管理單體表單控件的值和有效性狀態(tài)。它對應(yīng)于 HTML 的表單控件,比如 <input> 或 <select>。

FormGroup

管理一組 AbstractControl 實(shí)例的值和有效性狀態(tài)。該組的屬性中包括了它的子控件。組件中的頂層表單就是 FormGroup。

FormArray

管理一些 AbstractControl 實(shí)例數(shù)組的值和有效性狀態(tài)。

FormBuilder

一個(gè)可注入的服務(wù),提供一些用于提供創(chuàng)建控件實(shí)例的工廠方法。

指令

指令

詳情

FormControlDirective

把一個(gè)獨(dú)立的 FormControl 實(shí)例綁定到表單控件元素。

FormControlName

把一個(gè)現(xiàn)有 FormGroup 中的 FormControl 實(shí)例根據(jù)名字綁定到表單控件元素。

FormGroupDirective

把一個(gè)現(xiàn)有的 FormGroup 實(shí)例綁定到 DOM 元素。

FormGroupName

把一個(gè)內(nèi)嵌的 FormGroup 實(shí)例綁定到一個(gè) DOM 元素。

FormArrayName

把一個(gè)內(nèi)嵌的 FormArray 實(shí)例綁定到一個(gè) DOM 元素。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號