先前我對 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'
})
])
})

form.value

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

注意 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