Search code examples
javascriptangular

angular *ngFor not re-render html table with input


I am stuck with a very weird issue with angular. I have created one simple array in my ts file and I am displaying a table with input by iterating the same array. Now when I change the array (reverse it) it's working fine but if I have entered something in input before changing it, text will stay in input.

here is the code

component.ts

    import { Component } from '@angular/core';

    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'practice';
      myArray = [1,2,3,4,5,6,7];
      change() {
        // this.myArray = [];
        this.myArray.reverse();

      }
    }

my HTML:

    <html>
      <table>
        <tr *ngFor="let item of myArray; let i = index">
          <td>
            <input type="text" [value]='item'>
          </td>
        </tr>
      </table>
      <button (click)="change()">Change</button>
    </html>

Sample video for issue explanation: https://www.loom.com/share/6f4887183bb94150ad7390f25e5b466a

So as you can see, when I enter something in the input and change the array the value stays with array. I have checked the original array is not changing.

I mean it just got reversed, but nothing else.

What is the issue?


Solution

  • You should use trackby:

    <table>
        <tr *ngFor="let item of myArray; let i = index ;trackBy: trackItem" >
          <td>
            <input type="text" [value]='item' >
          </td>
        </tr>
      </table>
      <button (click)="change()">Change</button>
    

    in ts:

    trackItem (index, item) {
        return this.myArray ? this.myArray : undefined;
      }
    

    and if you want to keep that value you should bind it using ngModel:

    <table>
        <tr *ngFor="let item of myArray; let i = index ;trackBy: trackItem" >
          <td>
            <input type="text" [value]='item' [(ngModel)]="myArray[i]" >
          </td>
        </tr>
      </table>
      <button (click)="change()">Change</button>
    

    check this Demo

    Why using trackby:

    By default, when you use *ngFor without trackBy, *ngFor tracks array of objects changing through object identity. So, if new reference of array of objects is passed to the directive, even if the array is with the same values, Angular will not be able to detect that they are already drawn and presented in the current DOM. Instead, old elements will be removed and a new collection with the same values will be redrawn. We can help Angular to track which items added or removed by providing a trackBy function. The trackBy function takes the index and the current item as arguments and needs to return the unique identifier for this item. Now when you change the collection, Angular can track which items have been added or removed according to the unique identifier and create or destroy only the items that changed.

    Use trackBy when:

    1 - Iterating over large array of objects collection

    2 - Your business logic might need to modify any of these elements through reordering, modifying specific item, deleting item, or adding a new one