1

I have an edit component with the following html:

<form #productForm="ngForm" (ngSubmit)="save(productForm.value)">
...    
  <table>
    <thead>
    <tr>
      <th>blah</th>
      <th>blah</th>
      <th>blah</th>`
      <th>blah</th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let contact of product.contacts; let i = index">
      <input type="hidden" [(ngModel)]="contact.id" name="contact[{{i}}].id"/>
      <td>
        <input [(ngModel)]="contact.contact" type="text" name="contact[{{i}}].contact"/>
      </td>
      <td>
        <input [(ngModel)]="contact.email" type="text" name="contact[{{i}}].email"/>
      </td>
      <td>
        <input [(ngModel)]="contact.phone" type="text" name="contact[{{i}}].phone"/>
      </td>
      <td>
        <button type="button" (click)="deleteContact(i)">Delete</button>
      </td>
    </tr>
    </tbody>
  </table>

  <button type="button" (click)="addContact()">Add</button>    
  <button type="submit">Save</button>
</form>

Here's the deleteContact(i) method implementation:

 deleteContact(index) {
    this.product.contacts.splice(index, 1);
 }

When I have two contact rows, and I delete the first one while inspecting the elements, the indices of the second row's inputs decrement and they update from

<input _ngcontent-c1="" type="text" ng-reflect-name="contact[1].contact" ng-reflect-model="" class="ng-pristine ng-valid ng-touched">

to

<input _ngcontent-c1="" type="text" ng-reflect-name="contact[0].contact" ng-reflect-model="" class="ng-pristine ng-valid ng-touched">

But when I click save, the form parameter in my method still keeps all the contact information with the keys with index of 1 - "contact[1].contact". I've tried this workaround by adding this line in the end of my deleteContact method:

this.product.contacts = this.product.contacts.slice();

I also tried using ChangeDetectorRef.detectChanges(), but nothing helps. I can't understand why the indices decrement automatically on the front-end, and why the old index is in params. Any ideas?

Thanks.

V V
  • 159
  • 2
  • 10

2 Answers2

1

You can achieve a deletion by filtering:

deleteContact(_index) {
   this.product.contacts = this.product.contacts.filter((element, index) => index !== _index);
}
  • If I'm not mistaken, `splice()` method returns only the deleted elements, so that's not gonna work for me. – V V Apr 04 '18 at 15:20
  • Point taken. I edited my answer and provided another solution. –  Apr 04 '18 at 15:29
1

Try with a custom track by function.

*ngFor="let contact of product.contacts; let i = index; trackBy: customTB"

customTB(index, item) {
  return index + ' - ' + item.id;
}

When you use ng Model within a loop, this will always happen.

Also, you will need to use ngModel like this

[(ngModel)]="product.contacts[i].id"
  • Seems like this solution worked, but I only added track by. Why do I need to change ngModel? – V V Apr 04 '18 at 15:35
  • Well if it works without it then go without it ! From what I remember reading, you had to change the syntaxes because angular had an issue with variable creation and model binding. But I can be (and apparently am) wrong ! Anyway, good to know it worked. –  Apr 04 '18 at 15:39