Angularのリアクティブフォームではtsファイル側でネストした構成を組むことができます。
HTMLファイルでもformGroupやformControlの名前を定義できるのですが、
tsファイルで定義した構成に合うようにしてあげる必要があります。
構成に誤りがあると、以下のようなエラーが出たりします。
ERROR Error: formControlName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class).
それでは例で見てみましょう。
htmlで構成を再現する
formGroupName、formControlName、formArrayNameの3種類をうまく使って構成を組み上げてあげましょう。
それぞれFormControl、 FormGroup、FormArrayにNameがついただけなのでわかりやすいですね。
例えば、tsファイルで以下のような構成で組んだ場合。
~~ formGroup: FormGroup; roomMates: Array; constructor( private fb: FormBuilder ){} ngOnInit() { this.formGroup = this.fb.group({ firstName: [''], lastName: [''], address: this.fb.group({ street: [''], city: [''], state: [''], zip: ['111-1111'] }), frends: this.fb.array([ this.fb.control(''), this.fb.control('') ]) }); }
テキストボックスではhtml側では以下のように書けばOKです。
<form [formGroup]="formGroup"> <input type="text" formControlName="firstName"> // tsファイルでfirstNameとして設定したformControlと紐付け。 <input type="text" formControlName="lastName"> <div formGroupName="address"> // tsファイルでaddressと設定したformGroupと紐付け。 <input type="text" formControlName="street"> // ネストしたformControlはformGroupNameを設定した要素の中に配置 <input type="text" formControlName="city"> <input type="text" formControlName="state"> <input type="text" formControlName="zip"> </div> <div formArrayName="friends"> <div *ngFor="let roomMate of roomMates; index as i" > <input type="text" formControlName="{{i}}"> </div> </div> </form>
なお、tsファイル側だけで設定するということもあると思いますが、
html側にformControlNameが足りなくてもエラーになりません。
formArrayNameやformGroupNameが足りなくとどうなるか知りませんが、多分エラーにならないと思います。
コンポーネントを分割した場合
子コンポーネントに切り分けてあげる場合、親と同等に構造を書いてあげる必要があります。
上記の例のaddressの中を分割したとします。
<form [formGroup]="formGroup"> <input type="text" formControlName="firstName"> <input type="text" formControlName="lastName"> <div formGroupName="address"> <app-address-area [formGroup]="formGroup"></app-address-area> // address内をコンポーネント分割してformGroupを渡す。 </div> <div formArrayName="friends"> <div *ngFor="let roomMate of roomMates; index as i" > <input type="text" formControlName="{{i}}"> </div> </div> </form>
この場合、子コンポーネントでは以下のように書けばOKです。
<form [formGroup]="formGroup"> <div formGroupName="address"> <input type="text" formControlName="street"> <input type="text" formControlName="city"> <input type="text" formControlName="state"> <input type="text" formControlName="zip"> </div> </form>
普通はformGroupName=”address”ごと分割する方が良いですが、
多少わかり安いかなと思い上記のように書いてみました。