Angular 4 FormGroup removeControl() does not update the form

11.4k views Asked by At

I'm trying to figure out how to remove an element from a reactive form.

Here's a plunker of a small example: http://plnkr.co/edit/HyhMDoMtek02CyKpZ7Wt?p=preview

When I hit the X button, the form object is updated but the form UI still has the item on there.

How do I get the form to update itself on the remove?

2

There are 2 answers

1
Vova Bilyachat On BEST ANSWER

In template you are iterating over widgets

 <div *ngFor='let item of widget.items'>
            <input type='text' [formControlName]='item.id'>
            <button type='button' (click)='deleteItem(item.id)'>X</button>
          </div>

So what you need to do remove from widgets the from form

 deleteItem(id: number){
     var elem = this.widget.items.find((i)=>i.id == id);
     this.widget.items.splice(this.widget.items.indexOf(elem), 1)
    (<FormGroup>this.form).removeControl(id.toString());
  }

Other options would be instead of iterate via object iterate via controls object

<div *ngFor='let control of form.controls'>
   <input type='text' [formControl]='control'>
   <button type='button' (click)='deleteItem(item.id)'>X</button>
</div>
0
Jon Ediger On

My company experienced this issue while using FormGroups to dynamically add and remove controls on our angular based website.

Our software has a FormGroup that covers dynamically added/removed FormControls. As you add/remove widget.items entries, controls get added/removed from the shown page.

Any time you want to add a widget, you first add a new entry into the widget.items list then you add a new form control into the FormGroup (using FormGroup.addControl). The new control gets added to the bottom of the control list as expected, and any validators associated with the control would be added to it also. All existing controls maintain their data and validators.

If, on the other hand you remove a control from anywhere in the widget.items list other than the bottom, instead of removing the corresponding control on the page, Angular removes the bottom control. This will then cause all of the the controls at or below the now removed widget item to have the incorrect data, with the item at the now removed entry still containing the old information instead.

To fix this issue and let angular know it needs to update the whole form group correctly, you can do the following (assume widget.items = [widget1, widget2, widget3, widget4]):

  1. set widget.items to []

widget.items = []

  1. detect changes

this.changeDetectorRef.detectChanges()

  1. reset widget.items to the modified list (aka the list without the item to remove)

widget.items = [widget1, widget3, widget 4]

This will then cause the page list to be refreshed complete with valid data and working validators.

For our software this is required due to the way it handles custom controls and wires up the FormGroup/FormControl creation and life cycle. Hopefully this will help someone in a similar situation, but before you try this solution, try the strategy from the accepted answer as it's a cleaner way to go.