2
votes

Noticed a strange behavior with angular5 forms using the builder to construct a form which contains a form array needed to capture additional dynamic data, the form array values are only updated if

  1. During creation initial form controls where added to form array this.formBuilder.array(this.getRow())
  2. When the first initial control is touched

Angular version 5.2.0 Experimental/Sample Code Here

Point 1/2 Addendum

Changes appear to only be registered on components that are not dynamically added to FormArray

Code where form array element is inclusive of initialization process

  ngOnInit(){
    this.form = this.formBuilder.group({
      name:[null],
      description:[null],
      hobbies:this.formBuilder.array([this.getRow()])
    });
  }

  getRow():FormGroup{
    return this.formBuilder.group({
      hobby:[null],
      description:[null]
    });
  }

enter image description here

though it is evident that additional controls where created, they are all empty

However as soon as the first element is touched (noticed change from fishing to fishing4 and console output now has values of remaining dynamically added controls), all new dynamic fields values are propagated

enter image description here

2

2 Answers

3
votes

I had the same problem as you and, like you mentioned in your comment, the problem was that I was pushing the new controls on the .controls property of the form array.

So instead of

this.form.controls.xxx.controls.push(this.formBuilder.group(getGroup()));

you should go with

this.form.controls.xxx.push(this.formBuilder.group(getGroup()));

Later edit: Navigating the nested forms using the controls property doesn't make for the safest Angular updates. If they decide that the property will no longer be named controls in a future update to Angular, you're going to need to change quite a bit of code.

So instead of my previous code:

this.form.controls.xxx.push(this.formBuilder.group(getGroup()));

you should use

this.form.get('xxx').push(this.formBuilder.group(getGroup()));

This makes your code cleaner and future proofs it in case of any breaking changes to the controls property.

0
votes

In your html change:

<form [formGroup]="form.controls.hobbies">

and

  <tr *ngFor="let hobby of form.get('hobbies').controls; let r=index;" [formGroupName]="r">
     <td><input type="text" formControlName="hobby"></td>
     <td><input type="text" formControlName="description"></td>
  </tr>

by:

<div formArrayName="hobbies">
    <div *ngFor="let hobby of form.get('hobbies').controls; let r=index;">
        <div [formGroupName]="r">
             <td><input type="text" formControlName="hobby"></td>
             <td><input type="text" formControlName="description"></td>
        </div>
    </div>
</div>

Check this article:

https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2