39

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.

5
  • 1
    this.items.at(index).patchValue(...) doesn't work? Commented May 12, 2017 at 10:15
  • @developer033 Yeah it does , thank you, you can add that as an answer. Commented May 12, 2017 at 10:38
  • Maybe misunderstanding, but why are you creating an empty control first, if you want to set values to it? :) Commented May 12, 2017 at 12:48
  • @AJT_82 If the collection from the db is empty ( it can allow for an empty list with just a collection name ) then i want to initialize a default empty input when the page loads that the user can add their first value with Commented May 13, 2017 at 6:03
  • the naming of the collection and the adding collection items are in different views and have a sort of child parent relationship.. because each input in the FormGroup is a component which i am trying to create as generic as possible so i can use it site wide Commented May 13, 2017 at 6:10

5 Answers 5

52

Use FormArray#at + AbstractControl#patchValue:

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

DEMO

Sign up to request clarification or add additional context in comments.

1 Comment

A complete example would have made this answer whole.
10

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);

Comments

6

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]')

Comments

1

In TS file use below as an example

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

Comments

1
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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.