Search code examples
angularangular-reactive-formsformarrayform-controlformgroups

FormArray with nested FormGroups. How to access the nested form group controls?


I have a FormArray with 3 FormGroups and each form group has 2 controls. Im not sure how to access the controls within the form groups to set the form control name.

setting up the form

this.form = this.formBuilder.group({
---a couple controls---
properties: this.formBuilder.array({
  first: this.formBuilder.group({ 
   label: new UntypedFormControl(),
   value: new UntypedFormControl(),
  }),
  second: this.formBuilder.group({ 
   label: new UntypedFormControl(),
   value: new UntypedFormControl(),
  }),
  third: this.formBuilder.group({ 
   label: new UntypedFormControl(),
   value: new UntypedFormControl(),
  }),
})
})

getter for properties form array

get properties() {
  return this.form.controls.properties as FormArray;
}

im able to add and delete a row of properties.

html for the form. Am not sure how to access the label and value controls in each form group from the form array.

<div formArrayName="properties">
  <ng-container *ngFor="let propertiesForm of properties.controls; let i = index">
  <div [formGroupName]="i">
---then I have 3 sets of mat form fields each with and label and value---
  </div>
  </ng-container>
</div>

Solution

  • this.formBuilder.array() method only accepts a parameter which is an array. You can't provide an object to it.

    Approach 1: With this.formBuilder.array([])

    1. Modify your properties structure to an array.
    2. You can work with a loop to add the number of FormGroup that you need in the properties FormArray. And you should consider to implement a function to generate the single property FormGroup. This aims to reduce the code redundancy.
    ngOnInit() {
      // Form with Form Array
      this.form = this.formBuilder.group({
        //---a couple controls---
        properties: this.formBuilder.array([]),
      });
    
      for (let i = 0; i < 3; i++)
        this.properties.push(this.createPropertyFormGroup());
    }
    
    createPropertyFormGroup() {
      return this.formBuilder.group({
        label: new UntypedFormControl(),
        value: new UntypedFormControl(),
      });
    }
    
    <form [formGroup]="form">
      <div formArrayName="properties">
        <ng-container
          *ngFor="let propertiesForm of properties.controls; let i = index"
        >
          <div [formGroupName]="i">
            <label>Label: </label>
            <input formControlName="label" />
            <br />
    
            <label>Value: </label>
            <input formControlName="value" />
          </div>
          <hr />
        </ng-container>
      </div>
    </form>
    

    Approach 2: With this.formBuilder.group({})

    1. In HTML, you need the KeyValuePipe to iterate the properties FormGroup object and generate each FormGroup.
    this.form = this.formBuilder.group({
      //---a couple controls---
      properties: this.formBuilder.group({
        first: this.createPropertyFormGroup(),
        second: this.createPropertyFormGroup(),
        third: this.createPropertyFormGroup(),
      }),
    });
    
    get propertiesFormGroup() {
      return this.form.controls['properties'] as FormGroup;
    }
    
    <form [formGroup]="form">
      <div formGroupName="properties">
        <ng-container
          *ngFor="let propertiesForm of propertiesFormGroup.controls | keyvalue;"
        >
          <div [formGroupName]="propertiesForm.key">
            <label>Label: </label>
            <input formControlName="label" />
            <br />
    
            <label>Value: </label>
            <input formControlName="value" />
          </div>
          <hr />
        </ng-container>
      </div>
    </form>
    

    Demo @ StackBlitz