Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 FormGroup removeControl() does not update the form

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?

like image 742
Misha M Avatar asked Aug 31 '17 01:08

Misha M


People also ask

How do you append a new FormGroup or FormControl to form?

How to add a FormControl to a FormGroup. To add, update, or remove controls in FormGroup , use the following commands: addControl() adds a control and updates its value and validity. removeControl() removes a control.

Can't bind to FormGroup since it isn't a known property of form in Angular?

What Does This Error Mean? Angular is trying to tell us that it doesn't know about the formGroup directive on the <form> element in your component. This usually happens when the wrong forms module is imported, the right module is imported in the wrong place or the ReactiveFormsModule is just not imported at all.

How do I remove FormControl from Formarray?

The key here is to navigate your form structure. Once you get to the form group that _id is in, you can use removeControl('_id') to remove the control.


2 Answers

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>
like image 107
Vova Bilyachat Avatar answered Oct 07 '22 07:10

Vova Bilyachat


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.

like image 37
Jon Ediger Avatar answered Oct 07 '22 08:10

Jon Ediger