user1752532
user1752532

Reputation:

Angular 4 patchValue based on index in FormArray

I am looking to update a formArray after the user adds a value in an empty created control.

Currently when the user selects to add a new item i build onto the formArray with empty values.

buildItem(item?: any, key?: any): FormGroup {
  // Item will pass undefined for initial buildItem in onLoad and new items
  let itemName: string;
  let keyValue: string;
  if (item === undefined) { 
     itemName = ''; key = '' }  
  else { 
     itemName = item.name; keyValue = key 
  };

  /**
   * Builds a single item for form group array in the collectionForm.
   */
   return this.formBuilder.group({ 
                item: [itemName || '', Validators.required], 
                properties: { item, key: key } || {} });
}

This works fine for the initial creation and the update of items that are already added. The issue is with new items that are added with empty values. When i add a new item i need to add the return key from firebase in the properties.key

In the method for the save of that new item i added a patchValue

this.items.patchValue([{ 
         // item being returned from firebase promise
         item: item.name, 
         properties: { item: item.name, key: item.$key' } 
}]);

However the patchValue is not working at all. When i try the update that new value, although the values have been saved to firebase i still get a return for the values as empty or the save values set on the initial BuildItem() and not the updated values in the patchValue

I see on the angular FormArray Documentation that

It accepts an array that matches the structure of the control, and will do its best to match the values to the correct controls in the group. REF

Does that mean that it might and might not update that value .. it will just do its best to try? I figure if i can add the index for the value that i want to patch then it should not be a issue at all. like with the removeAt(idx)

So if i can write something like

this.form.patchValue.atIndex(this.idx,[{ 
         item: item.name, 
         properties: { item: item.name, key: item.$key' } 
}];

But not sure i can do that .. well pretty sure that it not possible in that form. Is there any way to specifically target the item that gets patched in a formArray or am i maybe not understanding this correctly.

I can sort of get away with this by pushing the new value onto the formArray

this.items.push(this.buildItem(...));

however then i have to add

this.items.removeAt(this.idx); 

In order to remove the initial control on the empty build , which does not seem like any sort of good code.

Upvotes: 39

Views: 67008

Answers (5)

developer033
developer033

Reputation: 24874

Use FormArray#at + AbstractControl#patchValue:

this.items.at(index).patchValue(...);

DEMO

Upvotes: 52

Menisha Myelwaganam
Menisha Myelwaganam

Reputation: 266

let rows = this.manageOrderForm.get('ordersForm') as FormArray;
    rows.controls[this.index].patchValue({totalAmount:totalPrice});
    this.index = this.index + 1;

formarray set value at index

((this.form.get('controls') as FormArray).at(index) as FormGroup).get('description').patchValue(item.description);

Upvotes: 1

tanuj khurana
tanuj khurana

Reputation: 11

In TS file use below as an example

let taskListArrays = this.projectParentForm.get('TaskList') as FormArray;
        
taskListArrays.controls[rowindex].patchValue({"Email":"[email protected]"};

Upvotes: 1

Altieri
Altieri

Reputation: 61

As developer033 said:

Use FormArray#at + AbstractControl#patchValue

But how to? Here's an example:

In the HTML:

<div formArrayName="alternateEmail" *ngFor="let control of alternateEmail.controls; index as i">
  <input type="text" placeholder="Type an alternative email" [formControlName]="i"><input>
</div>

In the class:

get alternateEmail(){  return this.registrationForm.get('alternateEmail') as FormArray }

And the actual patch method:

patchDynamicFormBlockValue(){
  this.alternateEmail.at(<index>).patchValue('[email protected]')
}

You can also remove the as FormArray and cast just when you need:

(<FormArray>this.alternateEmail).at(<index>).patchValue('[email protected]')

Upvotes: 6

abahet
abahet

Reputation: 10623

You can do this simply by creating a new FormControl if you want to update the hole array structure:

this.form.setControl('items',  new FormControl(arrayItemsValue));

Or by removing all items before updating them :

const items = (<FormArray>this.form.get('items'));
 for (let i = 0; i < items.length; i++) {
     items.removeAt(i);
 }
 this.form.get('items').setValue(arrayItemsValue);

Upvotes: 10

Related Questions