Search code examples
angularionic-frameworkangular-reactive-formsformarrayformgroups

Iterate a FormArray of FormGroups


I'm having trouble getting my form array of form groups to work.

I'd like to iterate over the form array and render the inputs in each form group. When I call addExercise() the template doesn't render the new form group that I push to the form array. Also when I call saveWorkout() the console.log(this.workoutFormArray.value) line shows that the values from my inputs are not reflected.

workout.component.ts

workoutFormArray: FormArray;

ngOnInit() {
  this.workoutFormArray = new FormArray([
    new FormGroup({
      exercise: new FormControl(''),
      reps: new FormControl('')
    })
  ]);
}

addExercise() {
  this.workoutFormArray.push(
    new FormGroup({
      exercise: new FormControl(''),
      reps: new FormControl(''),
    })
  );
}

saveWorkout() {
  console.log(this.workoutFormArray.value);
}

workout.component.html

<ion-icon (click)="addExercise()" name="add" slot="end"></ion-icon>

<div [formArrayName]="workoutFormArray">
  <div *ngFor="let group of workoutFormArray.controls; let i = index">
    <div [formGroupName]="i">
      <ion-select 
        placeholder="Exercise"
        formControlName="group.controls.exercise"
        (ionChange)="saveWorkout()"
      >
        <ion-select-option [value]="pushups"> Pushups </ion-select-option>
        <ion-select-option [value]="squats"> Squats </ion-select-option>
      </ion-select>

      <ion-input 
        type="text"
        formControlName="group.controls.reps"
      ></ion-input>
    </div>
    <button type="button" (click)="saveWorkout()">Save</button>
  </div>
</div> 

Solution

  • Updated: You mentioned that the workoutFormArray FormArray is the root of the form, you may have a read on this reported issue in GitHub: Supporting [formArray] without a [formGroup] parent #30264.

    <div [formGroup]="$any(workoutFormArray)">
      ...
    </div>
    

    The problem was that you provided the wrong formControlName to the nested FormGroup. It should be:

    <ion-select
      placeholder="Exercise"
      formControlName="exercise"
      (ionChange)="saveWorkout()"
    >
      <ion-select-option value="pushups"> Pushups </ion-select-option>
      <ion-select-option value="squats"> Squats </ion-select-option>
    </ion-select>
    
    <ion-input type="text" formControlName="reps"></ion-input>
    

    Without the prefix group.controls..

    Demo @ StackBlitz