Stefan Falk
Stefan Falk

Reputation: 25377

Error: Must supply a value for form control with name: <name>

I am having a nested operation in order to first remove an offer and then save it again as a repeating one.

The problem is, that after saving the repeating offer, I want to patchValue() the item in offerList[index]. This is where I am getting the error:

Error: Must supply a value for form control with name: 'id'.

Debugging however revealed that everything should be fine. The object saved in the final subscription has valid fields set. id is present and not null:

this._offerService.remove(this.placeId, offer)
  .pipe(
    flatMap((removed: OfferModel) => {
      // Re-use the removed offer to save a repeating one
      removed.id = null;
      removed.repeatWeekly = true;
      return this._offerService.save(this.placeId, removed)
        .pipe(finalize(() => this.updateOffersFormArray()));
    }),
  )
  .subscribe(
    (saved) => {
      console.log(saved);
      // offerList is either this.offers or this.repeatingOffers
      offerList[index].patchValue(saved);
    });

The console will log:

{id: 55, offerDate: "2019-03-04", …}

This is what happens in updateOffersFormArray():

// this.offersFormArray is a FormArray
updateOffersFormArray() {
  const tmp = this.repeatingOffers.concat(this.offers);
  console.log(tmp);
  this.offersFormArray.setValue(tmp); // <-- Throws error
}

The console ouput shows me an array of FormGroup elements, as expected, and each value of those FormGroup elements has an offer which has all the values set - especially id - which is according to the error message not set.

I'm scratching my head over this for quite some time now and I just don't see it.

I know the code looks a bit weird. After updateOffersFormArray() gets executed, the status change event of this.offersFormArray will update this.offers and this.repeatingOffers which I need for displaying purposes. Just to complete the picture, here is the code which does that:

this.offersFormArray.statusChanges.subscribe((e) => {
  const offers: Array<AbstractControl> = [];
  const repeatingOffers: Array<AbstractControl> = [];

  for (const k of Object.keys(this.offersFormArray.controls)) {
    const offerForm = this.offersFormArray.controls[k];
    const offer = <OfferModel> offerForm.value;

    if (offer.repeatWeekly) {
      repeatingOffers.push(offerForm);
    } else {
      offers.push(offerForm);
    }
  }

  this.offers = offers;
  this.repeatingOffers = repeatingOffers;
});

Upvotes: 1

Views: 8124

Answers (1)

Stefan Falk
Stefan Falk

Reputation: 25377

Turns out I was mistaken about setValue() of the FormArray. It does not accept a list of AbstractControl but instead it requires the values which match the structure of the control.

All I had to do was change

this.offersFormArray.setValue(tmp); 

to

this.offersFormArray.setValue(tmp.map(control => control.value));

Upvotes: 1

Related Questions