在Reactive Form使用陣列資料ーFormArray

前言

Reactive Form(嚮應式表單)可以很方便的處理表單裡的大小事務
若資料集是單純的陣列資料,則須配合FormArray使用

使用方式

FormBuilder.group()初始值

在form裡預設值直接傳前[]就好

constructor(private readonly fb: FormBuilder) { }  
   
this.form = this.fb.group({
 //...省略其他欄位...
 items: [[]],
})

直接console.log印出來會是

{
    items: []
}

無法直接patchValue傳值

一般由api取得內容後,要填入Reactive Form(嚮應式表單),可以直接用patchValue()填值
但formArray不行

須透過formBuilder.array封裝後,再使用setControl()填入

const items = MY_DATA_FROM_API.items; // ['a', 'b', 'c']
this.form.patchValue(MY_DATA_FROM_API); // 填入其他欄位內容
this.form.setControl('items', this.fb.array(items)); // 陣列元素須另外填入

異動formArray資料內容

增加元素:push

就如同陣列習慣,要增加元素就直接push
不能直接將元素單純push進去,須透過formBuilder.control(元素)封裝後再push

下例使用一般的input,綁定[(ngModal)]="itemValue"為例

addItem(): void {
  if (this.itemValue && !this.form.get('items').value.includes(this.itemValue)) {
    (this.form.get('items') as FormArray).push(this.fb.control(this.inputValue));
  }
  this.itemValue = ''; // 加入成功後,清除輸入框內容
}

刪除元素:removeAt(i)

在html裡的*ngFor指定i,直接傳入

removeItem(i: number) {
    (this.form.get('items') as FormArray).removeAt(i);
}

清除formArray

要透過removeAt逐一清除

clearItems() {
  while (this.form.get('items').value.length !== 0) {
    this.removeItem(0);
  }
}

或是暴力作法,直接重新放一個新的

clearItems() {
    this.form.setControl('items', this.fb.array([]));
}

缺點就是若有formArray.valueChanges的訂閱,會因遺失 reference 而出錯
較不建議採用此方式

參考資料

[Angular] FormArray 眉眉角角