Setting nested controls in FormArray with FormBuilder

1.2k views Asked by At

Here's an example:

  constructor(public fb: FormBuilder) {
    this.form = this.fb.group({
      foobars: this.fb.array([fb.group({ foo: null, bar: null })]),
      baz: null
    });

    const formValues = {
      foobars: [
        { foo: 1, bar: 'one'}
        { foo: 2, bar: 'two'}
      ],
      baz: 'baz'
    };

    this.form.reset(formValues);
  }

  addFoobar() {
    this.form.controls.foobars.push(this.fb.group({ foo: null, bar: null }))
  }

And a template:

<div>
  <div *ngFor="let foobar of form.controls.foobars.controls">
    foo: <input [formControl]="foobar.controls.foo" type="number">
    bar: <input [formControl]="foobar.controls.bar">
  </div>
  baz: {{ form.controls.baz.value }}
  <button (click)="addFoobar()">Add foobar</button>
</div>

The form is supposed to have variable amount of foo/bar control pairs. which are stored then as foobars array in database and retrieved as a plain object (formValues is static in this example, but in reality it is not).

The problem is that reset doesn't create nested controls in foobars form array automatically, while I would expect that it will.

How can form value be set here with reset? Is creating foobar item manually as fb.group({ foo: ..., bar: ... })]) the only correct way to add/set nested controls?

1

There are 1 answers

0
Andriy On

you can try to restructure your constructor like:

constructor(public fb: FormBuilder) {
  this.form = this.fb.group({
    foobars: this.fb.array([]),
    baz: null
  });

  this.addFoobar = () => {
    this.form.controls.foobars.push(this.fb.group({ foo: null, bar: null }))
  }  

  const formValues = {
    foobars: [
      { foo: 1, bar: 'one'}
      { foo: 2, bar: 'two'}
    ],
    baz: 'baz'
  };
  formValues.foobars.map(this.addFoobar);

  this.form.reset(formValues);
}
  1. foobars form array is created by FormBuilder with empty array
  2. foobars form array is filled with initial entries using formValues.foobars.map() function which executes addFoobar() for each iteration.
  3. form is updated by executing this.form.reset(formValues)

@DeborahK, I disagree with you about

You can't use setValue to set a FormArray

here is this function: https://github.com/angular/angular/blob/c59c390cdcd825cca67a422bc8738f7cd9ad42c5/packages/forms/src/model.ts#L1221.

On updated plunker I added the button 'Set value for form array' which is enabled when there are exactly 3 array items, clicking the button will update form array with setValue() function:

setFaValue() {
  this.form.get('foobars').setValue([
    { foo: 10, bar: 'one0'},
    { foo: 20, bar: 'two0'},
    { foo: 30, bar: 'three0'}
  ]);
}

updated plunker: http://plnkr.co/edit/XALYC8hUxkY0hIJrGLHx?p=preview