Reactive Formで、
FormGroup
でフォームを入れ子にした場合のFormControl
の得方が毎回わからなくなるのでメモ
今回のサンプルに使うフォーム定義は以下のようにします。
this.form = new FormGroup({
name: new FormControl('国会議事堂', Validators.required),
age: new FormControl(84, Validators.required),
address: new FormGroup({
zipcode: new FormControl('100-0014'),
prefecture: new FormControl('東京都'),
detail1: new FormControl('千代田区永田町1-7-1'),
detail2: new FormControl(''),
}),
})
ネストしたFormControl、FormGroupを得たい
上記のフォームで、this.form.controls
の結果は以下のようになる
controls:
address: FormGroup
...
controls:
detail1: FormControl
detail2: FormControl
prefecture: FormControl
zipcode: FormControl
age: FormControl
name: FormControl
なので、controls
プロパティを噛ませてやる必要がある。
例えば、detail2
を得たい場合
form.controls.address.controls.detail2
としなければならない。
controls乱発を避けるためのtips
エイリアスとなるgetterを定義
特にテンプレート側でFormControl
を得たい場合が多々あるが、controls
が乱発して可読性が低下することがある。
例えば今回の場合入れ子になっているaddress
というFormGroup
を、コンポーネント変数として宣言するとシンプルに書ける。
これは公式ドキュメントでも推奨のテクニック: https://angular.jp/guide/reactive-forms#creating-dynamic-forms
get formAddress(): FormGroup {
return this.form.get('address') as FormGroup
}
[formGroup]
ディレクティブに適用する場合
今回だとネストがそこまで深くないが、もっと深くなった場合は可読性がだいぶ変わりそう。
before
<div [formGroup]="form.controls.address">
after
<div [formGroup]="formAddress">
formGroupディレクティブをつけた要素の配下は、formControlディレクティブではなく、formControlNameディレクティブを使用する
上記のgetterとの合わせ技で、更に見やすくなる。
before
<div [formGroup]="formAddress">
<input type="text" [formControl]="formAddress.controls.detail1">
<input type="text" [formControl]="formAddress.controls.detail2">
after
<div [formGroup]="formAddress">
<input type="text" formControlName="detail1">
<input type="text" formControlName="detail2">
フォーム値(value)を得たい
値を得たい場合はFormControl
とは違って圧倒的に話は簡単で、
今回のサンプルで言えばthis.form.value
の結果が以下のようなkey-valueオブジェクトになっている。
{
address: {
zipcode: '100-0014',
prefecture: '東京都',
detail1: '千代田区永田町1-7-1',
detail2: '',
},
age: 84,
name: '国会議事堂',
}
ネストした要素も、素直に
form.value.address.detail2
のようにアクセスすれば良い。