Angular 2 - Can't set form array value

Chrillewoodz picture Chrillewoodz · Mar 14, 2017 · Viewed 20.8k times · Source

I get this error:

There are no form controls registered with this array yet. If you're using ngModel, you may want to check next tick (e.g. use setTimeout).

When using this code:

public settingsForm: FormGroup = this.fb.group({
  collaborators: this.fb.array([]),
  rsvp: this.fb.group({
    latestDate: ['', [Validators.required]],
    latestTime: ['', [Validators.required]],
    guestLimit: ['', [Validators.required]],
    isRSVPOpen: false,
    isGuestPlusOne: false,
    isAutoApproveToGuestlist: false,
    isOnlyFacebookRSVP: false,
    isBirthdayAndPhoneRequired: false
  }),
  tickets: this.fb.group({
    info: this.fb.group({
      closingDate: '',
      closingTime: ''
    }),
    types: this.fb.array([])
  })
});

Inside ngOnInit:

this.eventSubscription = this.af.database.object('/events/' + this.eventId)
  .filter(event => event['$value'] !== null)
  .subscribe((event: IEvent) => {

    const settings: ISettings = event.settings;
    const collaborators: ICollaborator[] = settings.collaborators;
    const rsvp: IRSVP = settings.rsvp;
    const tickets: ITickets = settings.tickets;

    this.settingsForm.setValue({
      collaborators: collaborators || [],
      rsvp: rsvp,
      tickets: {
        info: tickets.info,
        types: tickets.types || []
      }
    });
  }
);

When collaborators contains a value, i.e it's not undefined, null or empty [], something like:

[
  {
    email: '[email protected]',
    role: 1
  },
  {
    email: '[email protected]',
    role: 2
  }
]

Then the app crashes on the setValue line in the eventSubscription.

I cannot figure out why this is happening.

Any ideas?

Answer

Jingshao Chen picture Jingshao Chen · Sep 24, 2019

Before calling setValue(data) on a FormGroup or FormArray, the FormGroup or FormArray must have the exactly same structure of the data. Only the structure matters, the value in the FormGroup or FormArray will be replaced by data.

Example, if your data is

let data = [ {a: 1, b:2}, {a: 3, b: 4} ]

Then the FormArray must has 2 FormGroups and each FormGroup must has one FieldControl called a and one called b. You can do something like this:

let fa = this.formBuilder.array([
  this.formBuilder.group({a: 0, b:0}),
  this.formBuilder.group({a: 0, b:0})
])
fa.setValue(data)

If your data is of more complex structure, the FormArray needs to have the same complex structure.