3
votes

I've got a form that has the ability to add/remove rows of items. Whenever I want to go to edit my form, I run an asynchronous call to grab some data then patch/set the values of the form controls accordingly. Everything works as expected, however, with my rows of items, when I utilize Angular 2's patchValue function, it only patches a form group with the first object of an array of objects, instead of all of the objects.

So for example, if my form had 3 rows of line items, like in an invoice, only the first one is being populated. Can anyone tell me what I'm doing wrong?

Here is my component functionality

constructor() {
    this.createCheckRequestForm();
}

createCheckRequestForm() {
    this.createRequestForm = this._fb.group({
      issued_date: [new Date().toISOString(), [<any>Validators.required]],
      due_date: [new Date().toISOString(), [<any>Validators.required]],
      invoice_number: ['', [<any>Validators.required]],
      how_to_send: ['Mail', [<any>Validators.required]],
      normal_processing: ['', []],
      is_corporation: ['', []],
      line_items: this._fb.array([this.initLineItem()])
    });
  }

  /**
   *  Init the line item for the form builder
   */
  initLineItem(options?) {
    return this._fb.group({
        description: ['', []],
        coding: ['', []],
        amount: ['', []],
        line_item_types: [[], []]
    });
  }


populateFormWithRequest(requestId) {
    this.formPopulationObs = this._checkRequests.getRequest(requestId).subscribe(requestData => {




      // Iterate through the line items and patch them
      let lineItems = [];
      requestData.line_items.forEach((lineItem, index) => {

        let lineItemTypes = [];
        if(lineItem.line_item_types) {
          lineItemTypes = lineItem.line_item_types;
        }

        // Separate key-store for the coding dropdown models
        this.lineItemCodings[index] = lineItem.coding;

        let lineItemObj = {
          description: lineItem.description,
          coding: lineItem.coding,
          amount: lineItem.amount,
          line_item_types: lineItemTypes,
        }
        lineItems.push(lineItemObj);
      })

      this.createRequestForm.patchValue({line_items: lineItems});
  })
}

If I have an array like this, only the first element shows up in the "patch"

[ 
 {amount: "600", coding: "-Kfxw732pfWUS5rU0TRu", description: "Cameras"},
 {amount: "600", coding: "-Kfxw732pfWUS5rU0TRu", description: "Lights"}
]

Thanks in advance!

2
Take a look at this: stackoverflow.com/questions/41645677/…. Some of the concepts might help you. - R. Richards
based on that question/answer recommended by @R.Richards, you have to loop through your FormArray and patch each item individually - snorkpete
Hmmm after referencing the examples in that post, I'm getting an error: `Property 'at' does not exist on type 'AbstractControl'. What gives? :/ - Stevie Star
Okay, so I got the error to go away, but the problem is that my code seems to want to patch line_items that don't exist in the form yet. By default, the form creates only 1 line_item and if I try to patch 3 line_items, it only gets the first one, since only one has been instantiated, I believe. - Stevie Star

2 Answers

3
votes

Alright, so in order to get this to work, I had actually push form group array elements onto the "line_items" control that already existed THEN patch the values. Here is my updated function:

populateFormWithRequest(requestId) {
    this.formPopulationObs = this._checkRequests.getRequest(requestId).subscribe(requestData => {


      // Iterate through the line items and patch them
      requestData.line_items.forEach((lineItem, index) => {

        let lineItemTypes = [];
        if(lineItem.line_item_types) {
          lineItemTypes = lineItem.line_item_types;
        }

        // Create the item obj
        let lineItemObj = {
          description: lineItem.description,
          coding: lineItem.coding,
          amount: lineItem.amount,
          line_item_types: lineItemTypes,
        }

        const control = <FormArray>this.createRequestForm.controls['line_items'];
        control.push(this.initLineItem());
        control.at(index).patchValue(lineItemObj);
      });
  })
}
0
votes

The same result, a little bit easier - without creating a empty item and overwriting it:

populateFormWithRequest(requestId) { 
  this.formPopulationObs = this._checkRequests.getRequest(requestId).subscribe(requestData => { 
    this.createRequestForm["line_items"] = 

requestData.line_items.forEach(itm=>(<FormArray>this.createRequestForm["line_items"]).push(this.createRequestForm.group(itm)));

)); 
}); 
}