Angular 2: Cannot add a group of forms to form an array in reactive forms

I am creating a dynamic form and want to add form groups on the fly.

Here is my code that almost works:

import {Component, OnInit} from '@angular/core';
import {FormGroup, FormBuilder, FormArray, Validators, FormControl} from "@angular/forms";

export class CombinedComponent implements OnInit {

    ltsForm: FormGroup;

    constructor(private formBuilder: FormBuilder) {
    }

    ngOnInit() {
        this.ltsForm = this.initFormGroup();

        // init products
        for (let i = 0; i < 3; i++) { // add dynamically products
            this.addProduct();
        }

        console.log(this.ltsForm); // Array 'prods' is empty
    }

    // initialize form group, but don't add products yet because they will be added dynamically later
    initFormGroup() {
        let group = this.formBuilder.group({
            products: this.initProductGroup()
        });

        return group;
    }

    initProductGroup() {
        let group = this.formBuilder.group(
            {
                //initialize empty formbuilder array
                prods: this.formBuilder.array([])
            }
        );

        return group;
    }

    initProducts() {
        return this.formBuilder.group({
            id: [''],
            value: false, // checkbox value
        });
    }

    addProduct() {
        <FormArray>this.ltsForm.controls['products'].value.prods.push(this.initProducts());

        console.log(this.ltsForm); // Array 'prods' contains 3 FormGroup elements
    }
} 

Template:

<form [formGroup]="ltsForm"
      novalidate
      (ngSubmit)="save(ltsForm)">

    <div formGroupName="products">
        <div formArrayName="prods">

            <div *ngFor="let product of ltsForm.controls.products.value.prods.controls; let i = index">
                <div [formGroupName]="i">
                    <input type="checkbox"
                           formControlName="value"
                           id="product_{{ i }}"
                           name="product_{{ i }}">
                </div>
            </div>

        </div>
    </div>

    <button type="submit"
            [disabled]="!ltsForm.valid">
        Submit
    </button>
</form>

In the addProduct () method, I pop the entire FormGroup element into the 'prods' array. Therefore, at the end, the output from the console in ngOnInit () contains only the empty "prods" array, while the array from the console output from the addProduct () method has 3 elements. It seems that this.ltsForm is losing its link and not being updated. Any ideas?

UPD: just found out that if I delete all the content from the template, I get "prods" filled with data.

+4
source share
1 answer

, . Angular , . ( plnkr):

  • : { projects: '' }.
  • : { projects: ['a', 'b', 'c'] }. prods, .

    <form [formGroup]="ltsForm" novalidate (ngSubmit)="save()">
      <div formArrayName="products">
        <div *ngFor="let p of products.controls; let i=index">
          <input [formControlName]="i">
        </div>
      </div>
      <button type="submit" [disabled]="!ltsForm.valid">
        Submit
      </button>
    </form>
    
    ...
    
    export class CombinedComponent implements OnInit {
    
      ltsForm: FormGroup;
    
      get products() { return this.ltsForm.get('products'); }
    
      constructor(private formBuilder: FormBuilder) {}
    
      ngOnInit() {
          this.ltsForm = this.formBuilder.group({
            products: this.formBuilder.array([])
          });
    
          for (let i = 0; i < 3; ++i) {
            this.addProduct();
          }
      }
    
      addProduct() {
        this.products.push(this.formBuilder.control(''));
      }
    
      save() {
        console.log(this.ltsForm.value);
      }
    } 
    
  • :

    @Component({
      selector: 'combined-component',
      template: `
        <form [formGroup]="ltsForm" novalidate (ngSubmit)="save()">
          <div formArrayName="products">
            <div *ngFor="let p of products.controls; let i=index">
              <div [formGroupName]="i">
                <input formControlName="id">
                <input type="checkbox" formControlName="value">
              </div>
            </div>
          </div>
          <button type="submit" [disabled]="!ltsForm.valid">
              Submit
          </button>
        </form>
      `
    })
    export class CombinedComponent implements OnInit {
    
      ltsForm: FormGroup;
    
      get products() { return this.ltsForm.get('products'); }
    
      constructor(private formBuilder: FormBuilder) {}
    
      ngOnInit() {
          this.ltsForm = this.formBuilder.group({
            products: this.formBuilder.array([])
          });
    
          for (let i = 0; i < 3; ++i) {
            this.addProduct();
          }
      }
    
      addProduct() {
        this.products.push(this.formBuilder.group({
          id: '',
          value: false
        }));
      }
    
      save() {
        console.log(this.ltsForm.value);
      }
    } 
    
+10

Source: https://habr.com/ru/post/1666064/


All Articles