Search code examples
javascriptangular

Angular2 FormArray insert does not update view accordingly


So I have a FormArray containing FormGroups with 3 controls. Visually it looks like a table with 3 inputs on each row. Here is how it looks:

enter image description here

I want when the user presses tab or enter at the last input in the row - a new empty row to be added after it. So I added (keydown)="addRow($event.keyCode, i)" to the last input and created the function:

public addRow(keyCode, index)
{
    if (keyCode !== 9 && keyCode !== 13) {
        return;
    }

    let formItems = this.form.get('items') as FormArray;

    formItems.insert(
        index + 1,
        this.formBuilder.group({
            'start': ['', Validators.required],
            'title': ['', Validators.required],
            'category': [''],
        })
    );
}

Afther the FormGroup is pushed, I can see the controls correctly in the form array, however the view is updated strangely. After for example I press tab on the last input in the first row I get this result:

enter image description here

Last row is removed and I get two empty rows in the after the first. I couldn't find out why. Here is the FormArray after the push, the items are OK there:

enter image description here

Here is the view code:

<div formArrayName="items">
    <div *ngFor="let item of form.controls.items.controls; let i=index" [formGroupName]="i" class="row item-index-{{ i }}">
        <div class="form-group">
            <div class="col-sm-2">
                <input type="text" class="form-control" placeholder="Start" autocomplete="off" formControlName="start">
            </div>
            <div class="col-sm-4">
                <input type="text" class="form-control" placeholder="Title" autocomplete="off" formControlName="title">
            </div>
            <div class="col-sm-4">
                <input type="text" class="form-control" placeholder="Category" autocomplete="off" formControlName="category" (keydown)="addRow($event.keyCode, i)">
            </div>
            <div class="col-sm-2">
                <a class="btn btn-icon-only default">
                    <i class="fa fa-arrow-up"></i>
                </a>
                <a class="btn btn-icon-only default">
                    <i class="fa fa-arrow-down"></i>
                </a>
                <a class="btn btn-icon-only red">
                    <i class="fa fa-times"></i>
                </a>
            </div>
        </div>
    </div>
</div>

Any idea why this happens?


Solution

  • I've encountered this issue once earlier when not inserting formgroup at the end of formarray. Seems Angular is having trouble tracking the index in template for some reason, and by using trackBy solved it. So try:

    <div *ngFor="let item of form.get('items').controls; let i=index; trackBy:trackByFn" 
                [formGroupName]="i" class="row item-index-{{ i }}">
    

    and in TS:

    trackByFn(index: any, item: any) {
      return index;
    }