Reactive Forms: 使用 FormArray

FormArray 的基本概念

當需要處理動態數量的表單控制項時,例如一組複選框、多個輸入欄位或可新增/刪除的表單區塊,FormArray 是一個非常有用的工具。

不同於 FormGroup 使用名稱來組織控制項,FormArray 使用索引來組織,類似於一般的陣列。

基本用法

在 TypeScript 中定義 FormArray

import { FormGroup, FormControl, FormArray } from '@angular/forms';

@Component({...})
export class MyComponent {
  myForm = new FormGroup({
    name: new FormControl(''),
    email: new FormControl(''),
    // 使用 FormArray 處理多個複選框
    interests: new FormArray([
      new FormControl(false), // 第一個複選框,預設未選中
      new FormControl(false), // 第二個複選框,預設未選中
      new FormControl(false), // 第三個複選框,預設未選中
    ]),
  });
}

在範本中使用 FormArray

<form [formGroup]="myForm">
  <div>
    <label for="name">Name</label>
    <input id="name" formControlName="name">
  </div>
  
  <div>
    <label for="email">Email</label>
    <input id="email" formControlName="email">
  </div>
  
  <div formArrayName="interests">
    <h3>What are you interested in?</h3>
    
    <div>
      <input type="checkbox" id="coding" [formControlName]="0">
      <label for="coding">Coding</label>
    </div>
    
    <div>
      <input type="checkbox" id="music" [formControlName]="1">
      <label for="music">Music</label>
    </div>
    
    <div>
      <input type="checkbox" id="sports" [formControlName]="2">
      <label for="sports">Sports</label>
    </div>
  </div>
  
  <button type="submit">Submit</button>
</form>

注意在範本中,我們:

  1. 使用 formArrayName 指定要訪問的 FormArray

  2. 使用 [formControlName]="index" 綁定 FormArray 中的各個控制項,這裡的 index 是數字索引

訪問 FormArray 的值

可以通過以下方式訪問 FormArray:

// 獲取整個 FormArray
const interestsArray = this.myForm.get('interests') as FormArray;

// 獲取特定控制項
const codingControl = interestsArray.at(0);

// 獲取 FormArray 的所有值
const allInterests = interestsArray.value; // [false, false, false]

// 檢查特定值
console.log(interestsArray.at(0).value); // false

動態操作 FormArray

FormArray 最強大的特性是能夠動態添加和刪除控制項:

// 獲取 FormArray 引用
get interestsArray() {
  return this.myForm.get('interests') as FormArray;
}

// 添加新的控制項
addInterest() {
  this.interestsArray.push(new FormControl(false));
}

// 移除控制項
removeInterest(index: number) {
  this.interestsArray.removeAt(index);
}

// 重置所有控制項
resetInterests() {
  this.interestsArray.clear();
  // 添加預設控制項
  this.interestsArray.push(new FormControl(false));
  this.interestsArray.push(new FormControl(false));
}

配合動態範本:

<div formArrayName="interests">
  <h3>What are you interested in?</h3>
  
  @for (interest of interestOptions; track $index) {
    <div>
      <input 
        type="checkbox" 
        [id]="'interest-' + $index" 
        [formControlName]="$index"
      >
      <label [for]="'interest-' + $index">{{ interest }}</label>
      <button type="button" (click)="removeInterest($index)">Remove</button>
    </div>
  }
  
  <button type="button" (click)="addInterest()">Add Interest</button>
</div>

複雜的 FormArray 用例

FormArray 也可以包含 FormGroup,用於處理更複雜的場景:

// 動態添加地址
addressForm = new FormGroup({
  addresses: new FormArray([
    new FormGroup({
      street: new FormControl(''),
      city: new FormControl(''),
      postalCode: new FormControl('')
    })
  ])
});

// 添加新地址
addAddress() {
  const addresses = this.addressForm.get('addresses') as FormArray;
  addresses.push(
    new FormGroup({
      street: new FormControl(''),
      city: new FormControl(''),
      postalCode: new FormControl('')
    })
  );
}
<form [formGroup]="addressForm">
  <div formArrayName="addresses">
    @for (address of addressForm.get('addresses')['controls']; track $index) {
      <div [formGroupName]="$index">
        <input formControlName="street" placeholder="Street">
        <input formControlName="city" placeholder="City">
        <input formControlName="postalCode" placeholder="Postal Code">
        <button type="button" (click)="removeAddress($index)">Remove</button>
      </div>
    }
    <button type="button" (click)="addAddress()">Add Address</button>
  </div>
</form>

FormArray 的優勢

  1. 處理動態數量的控制項:當不確定表單會有多少個控制項時特別有用

  2. 批量操作:可以方便地對多個控制項進行批量操作

  3. 索引訪問:通過索引可以直接訪問特定控制項

  4. 靈活性:可以在執行時添加或刪除控制項

小結

FormArray 是處理動態表單控制項的強大工具,尤其適用於:

  • 多個複選框

  • 動態添加/刪除的表單項

  • 可變數量的相同結構表單區塊

當有一組相似的表單控制項,或需要根據用戶操作動態調整表單結構時,考慮使用 FormArray

Last updated