在Reactive Form使用陣列資料ーFormArray

前言

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

使用方式

FormBuilder.group()初始值

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

1
2
3
4
5
6
constructor(private readonly fb: FormBuilder) { }  

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

直接console.log印出來會是

1
2
3
{
items: []
}

無法直接patchValue傳值

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

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

1
2
3
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"為例

1
2
3
4
5
6
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,直接傳入

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

清除formArray

要透過removeAt逐一清除

1
2
3
4
5
clearItems() {
while (this.form.get('items').value.length !== 0) {
this.removeItem(0);
}
}

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

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

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

參考資料

[Angular] FormArray 眉眉角角