Angular 2 - Can't set form array value
Asked Answered
M

4

17

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?

Misvalue answered 14/3, 2017 at 12:46 Comment(0)
R
2

Initialize the form array with the control. That would resolve the issue. See Reactive Forms guide if you need to know how to do that. If you are using ngModel it would probably worth to remove it.

Recollection answered 14/3, 2017 at 13:20 Comment(0)
H
7

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.

Harmonia answered 24/9, 2019 at 20:49 Comment(0)
R
2

Initialize the form array with the control. That would resolve the issue. See Reactive Forms guide if you need to know how to do that. If you are using ngModel it would probably worth to remove it.

Recollection answered 14/3, 2017 at 13:20 Comment(0)
S
1

You have to build your form OnInit before setting its value. Try something like this :

settingsForm: FormGroup; 

buildForm(): void {
   settingsForm: FormGroup = this.fb.group({
      //content of settingsForm
   })
}

ngOnInit() {
    this.buildForm();
    this.eventSubscription = this.af.database.object('/events/' + this.eventId)
    //...
    this.settingsForm.setValue({ //you can try .patchValue to set only available value
        //...
    })
}
Shippee answered 14/3, 2017 at 13:0 Comment(3)
That's exactly what I'm doing right away. you don't have to do it in the on init hook.Misvalue
ok, I had similar issue and this solved it. I thought it was the same issue :(. Did you check this blog post. Citation: "Providing your FormControl exists, Angular moves onto the Object.keys loop, however will first check that the control is missing for that value also via _throwIfControlMissing:"Shippee
Ye it was a problem with missing form group, so I had to loop over all the objects and then push a new group to the form array for each. Bit annoying and weird design choice.Misvalue
J
1

I think this code will help

 import { FormArray, FormBuilder, FormGroup} from '@angular/forms';

export class SomeComponent implements OnInit {

consutructor(public  fb:FormBuilder) { }

    public buildcollaboratorsGroup(fb:FormBuilder):FormGroup {
        return fb.group({
                            email:'',
                            role:''
                });
    }

ngOnInit() {
    public settingsForm: FormGroup = this.fb.group({
    collaborators:this.fb.array([this.buildcollaboratorsGroup(this.fb)])
    });     

    this.setFormArrayValue();
 }


    // I am trying set only one value if it's multiple use foreach        
    public setFormArrayValue() {
        const controlArray = <FormArray> this.settingsForm.get('collaborators');
        controlArray.controls[0].get('email').setValue('[email protected]');
        controlArray.controls[0].get('role').setValue(2);
    }

    // I am trying remove only one value if it's multiple use foreach        
    public removeFormArrayValue() {
        const controlArray = <FormArray> this.settingsForm.get('collaborators');
           controlArray.removeAt(0);        
    }
}
Jonna answered 16/8, 2017 at 7:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.