😄
[Angular]2次元配列のフォームを作成する
背景
実務で、2次元配列をフォームとして扱う実装を担当した。
しかし、そのやり方の文献が少なく、実装に苦労したため、今回の記事を残すことにした。
AngularのFormArrayに関して
AngularのReactiveFormには、FormArray
というフォームの値を配列形式で扱う仕組みが提供されている。
この機能を使うことで、配列の値から動的にフォームを生成することができる。
詳しくは、以下の公式ドキュメントを見ると良い。
実際に作ったもの
今回は、2次元配列から作成した表の中にチェックボックスが存在するサンプルを実装してみた。
チェックを押して、Submit
を行うと、画面下方にチェックしたrowとcolの値が出現するような仕様である。
イメージ画像
実際のコード
main.tsの解説
2次元配列フォーム作成に関する主要な部分を解説していく。
フォームの定義
以下のように、FormBuilder
インスタンスのarray
メソッドを使うことで、配列を表現することができる。
form: FormGroup = this.formBuilder.group({
row: this.formBuilder.array([]),
});
ソースコードを見るとわかるが、array
メソッドはFormArray
型を返している。
/**
* Constructs a new `FormArray` from the given array of configurations,
* validators and options. Accepts a single generic argument, which is the type of each control
* inside the array.
*
* @param controls An array of child controls or control configs. Each child control is given an
* index when it is registered.
*
* @param validatorOrOpts A synchronous validator function, or an array of such functions, or an
* `AbstractControlOptions` object that contains
* validation functions and a validation trigger.
*
* @param asyncValidator A single async validator or array of async validator functions.
*/
array<T>(controls: Array<T>, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormArray<ɵElement<T, null>>;
フォームの初期化
以下のコードで、フォームの初期化を行っている。
initForm(): void {
this.row.forEach((rowIndex) => {
const rowFormGroup = this.formBuilder.group({
col: this.formBuilder.array([]),
});
const colFormArray = rowFormGroup.get('col') as FormArray;
this.col.forEach((colIndex) => {
const colFormGroup = this.formBuilder.group({
row: rowIndex,
col: colIndex,
isChecked: false,
});
colFormArray.push(colFormGroup);
});
this.getFormArray().push(rowFormGroup);
});
}
イメージとして、以下のような構造のフォームを作成している。
form: FormGroup {
row: FormArray [
FormGroup {
col: FormArray [
FormGroup {
row: FormControl,
col: FormControl,
isChecked: FormControl,
},
...
],
},
...
],
}
HTMLの解説
フォームのコード
Angularにおいて、formGroup、formArrayNameなどのディレクティブはDOMとFormControl
をリンクするために使われる。
<form [formGroup]="form">
<table formArrayName="row">
<tbody>
<tr
*ngFor="let rowControl of getRowControls(); let rowIndex = index"
[formGroupName]="rowIndex"
>
<td formArrayName="col">
<label
*ngFor="let colControl of getColControls(rowControl); let colIndex = index"
[formGroupName]="colIndex"
>
<input type="checkbox" formControlName="isChecked" />
</label>
</td>
</tr>
</tbody>
</table>
</form>
フォームのディレクティブ
formGroup
フォーム全体のバインドを行う。
例
<form [formGroup]="myFormGroup">
myFormGroup = this.formBuilder.group({
...
});
formGroupName
子要素のFormGroupをDOMにバインドする。
例
<div formGroupName="user">
myFormGroup = this.formBuilder.group({
user: this.formBuilder.group({...})
});
formArrayName
FormArrayをDOMにバインドする。
例
<div formArrayName="">
myFormGroup = this.formBuilder.group({
groupList: this.formBuilder.array([...])
});
formControlName
FormControlをDOMにバインドする。
例
<input formControlName="userName">
myFormGroup = this.formBuilder.group({
userName: ['', Validators.required]
});
Discussion