LoginSignup
3
3

More than 3 years have passed since last update.

[Angular] FormGroupがネストしたReactive Formをうまく操りたい

Last updated at Posted at 2020-06-17

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

のようにアクセスすれば良い。

参考

Angular 日本語ドキュメンテーション - リアクティブフォーム

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3