Chris Rockwell
Chris Rockwell

Reputation: 1852

Iterate over FormArray to show form fields

I'm trying to get something going with reactive forms but having difficulty achieving what I thought would be straightforward.

I would like to loop over elements and display them as form controls.

I currently have:

@Component({
  selector: 'app-reactive-form-test',
  styleUrls: ['./reactive-form-test.component.scss'],
  template: `
    <form [formGroup]="questionForm">
      <ng-container formArrayName="questions" *ngFor="let question of questionForm.controls; let i = index">
<input type="text" formControlName="i">
</ng-container>
    </form>
  `
})
export class ReactiveFormTestComponent implements OnInit {
  questionForm: FormGroup;

  questions: ScheduledQuestionInterface[];

  constructor(private fb: FormBuilder) { }

  ngOnInit(): void {
    this.questionForm = this.fb.group({
      questions: this.fb.array([])
    });
    this.questions = [];
    this.questions.push(new ScheduledQuestion(1, 1, 1, 1));
    this.questions.push(new ScheduledQuestion(2, 3, 1, 2));
    this.questions.push(new ScheduledQuestion(3, 4, 1, 3));
    this.questions.forEach(value => {
      const control = this.questionForm.get('questions') as FormArray;
      control.push(this.fb.group({
        id: [value.id],
        deliveryDateTime: [value.deliveryDateTime]
      }));
    });
  }
}

Right now I'm getting the below error:

Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays..

What do I need to do to this code to simply show 3 text fields from the 3 ScheduledQuestion objects?

Upvotes: 4

Views: 8301

Answers (2)

Owen Kelvin
Owen Kelvin

Reputation: 15083

questionForm.controls is an Object with the keys as the formControls basically in your case

  {
     questions: []
  }

You are trying to loop over the above object which is not iterable hence the error

Below should work

@Component({
  selector: 'app-reactive-form-test',
  styleUrls: ['./reactive-form-test.component.scss'],
  template: `
    <form [formGroup]="questionForm">
      <ng-container formArrayName="questions">
        <ng-container *ngFor="let question of questionControls.controls; let i = index">
<input type="text" [formGroupName]="i">
      </ng-container>
      
</ng-container>
    </form>
  `
})
export class ReactiveFormTestComponent implements OnInit {
  questionForm: FormGroup;

  questions: ScheduledQuestionInterface[];
  get questionControls() {
     return this.questionForm.get('questions') as FormArray;
  }
  

  constructor(private fb: FormBuilder) { }

  ngOnInit(): void {
    this.questionForm = this.fb.group({
      questions: this.fb.array([])
    });
    this.questions = [];
    this.questions.push(new ScheduledQuestion(1, 1, 1, 1));
    this.questions.push(new ScheduledQuestion(2, 3, 1, 2));
    this.questions.push(new ScheduledQuestion(3, 4, 1, 3));
    this.questions.forEach(value => {
      const control = this.questionForm.get('questions') as FormArray;
      control.push(this.fb.group({
        id: [value.id],
        deliveryDateTime: [value.deliveryDateTime]
      }));
    });
  }
}

Upvotes: 5

Zac
Zac

Reputation: 1542

The issue here is that you are trying to loop over questionForm.controls, which is not iterable, it's an object, and it's not what you need, also you don't need to repeat the form array, you need to loop over the controls in this array

an example from Angular References:

<div formArrayName="cities">
  <div *ngFor="let city of cities.controls; index as i">
    <input [formControlName]="i" placeholder="City">
  </div>
</div>

so, you need to have NgFor for your inputs/controls, and the loop should be over questions.controls

Upvotes: 2

Related Questions