先前我對 FomrArray 一直有個誤解,就是以為在 Angular 的 Reactive Form 中,若表單裡的資料是 array 就要使用它;誰叫拿 angular 跟 form 、 array 三個關鍵字餵狗就會跑出它而事實上只要這樣寫就行了:

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

this.form = this.fb.group({
items: [[]]
})

若把 form.value console.log 出來就是:

1
2
3
{
items: [];
}

那 FormArray 的真正用途是什麼?主要是讓我們能「陣列式」管理表單的控制項與資料,例如以下的通訊錄表單:

1
2
3
4
5
6
7
8
9
10
11
12
13
constructor(
private fb: FormBuilder
) { }

this.form = this.fb.group({
title: ['My Contacts', Validators.required],
contacts: this.fb.array([
this.fb.group({
name: 'Jane Doe',
phone: '12345678'
})
])
})

每位聯絡人姓名與電話為一組在 contacts 陣列裡的物件,form.value 的資料結構會是:

1
2
3
4
5
6
7
{
title: 'My Contacts',
contacts: [{
name: 'Jane Doe',
phone: '12345678'
}]
}

要在 html 中 render,用 formArrayName 連結 form 裡的 formArray 屬性名稱 "contacts",而 contacts 控制項作為 formArray ,其 controls 屬性為可供遍歷的 formGroup 陣列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<form [formGroup]="form">
<div
formArrayName="contacts"
*ngFor="let contact of form.get('contacts').controls; let i = index"
>
<ng-container [formGroup]="contact">
<input
formControlName="name"
type="text"
/>
...
</ng-container>
</div>
</form>

注意 contacts 控制項並不是 JS array,Angular 定義的 FormArray 沒有像 splice() 等原生 JS 方法可用。

FormArray 操作

使用 push()

1
2
3
4
5
6
(<FormArray>this.form.get('contacts')).push(
this.fb.group({
name: 'John Doe',
phone: '3345678'
})
);

使用 removeAt(idx)

1
(<FormArray>this.form.get('contacts')).removeAt(idx);

patchValue

一般 form 裡面的資料可以用 patchValue()

1
2
3
this.form.patchValue({
title: 'Another Contacts'
});

對於 FormArray 資料另外用 setControl() 去覆蓋:

1
2
3
4
5
6
7
8
9
this.form.setControl(
'contacts',
this.fb.array([
this.fb.group({
name: 'John Doe',
phone: '3345678'
})
])
);

清空 FormArray

要清空 FormArray 的元素,讓它長度為 0 時,用 removeAt() 去遞迴,寫成 function:

1
2
3
4
5
clearFormArray = (formArray: FormArray) => {
while (formArray.length !== 0) {
formArray.removeAt(0)
}
}

另一個比較暴力的做法:

1
2
3
clearFormArray = (formArray: FormArray) => {
formArray = this.formBuilder.array([]);
}

副作用是若有對 formArray.valueChanges 的訂閱,將會丟失 reference 而出錯,不太推薦。

玩沙場

說那麼多不如來段可以玩的 code:

Reference