Search code examples
angularangular-ngmodelngmodelangular2-ngmodel

Using [(ngModel)] 2 way data binding with ngFor , array doesn't update the values of the rows


I have built this form: enter image description here

Here's the html code:

<table class="table table-hover table-bordered table-striped table-highlight">
  <thead>
    <tr>
      <th *ngFor="let cell of tableData2.headerRow">{{ cell }}</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let row of tableData2.dataRows">
      <td *ngFor="let cell of row">
        <input type="text" class="form-control border-input" [(ngModel)]="cell" name="cell" />
      </td>
    </tr>
  </tbody>
</table>

Here's the relevant typescript code:

declare interface TableData {
  headerRow: string[];
  dataRows: string[][];
}
public tableData2: TableData;
this.tableData2 = {
  headerRow: ['Version', 'Approbateur(nom+fonction)', 'Principales remarques', 'Date d\'approbation'],
  dataRows: [
    ['ahmed', '', '', ''],
    ['', '', '', ''],
    ['', '', '', ''],
    ['', '', '', ''],
    ['', '', '', ''],
    ['', '', '', ''],
    ['', '', '', ''],
  ]
};

As you may have noticed, the two-way data binding works in "one direction", the value "ahmed" does get displayed.
However, when I change the value of an input in a table like this:
enter image description here And then I consoleLog the tableData2 variable:
enter image description here As you may notice, the new value SAM doesn't get updated in the tabledata variable. I.e, the two-way data-binding doesn't work and I cannot retrieve the values from the table.
What did I do wrong?


Solution

  • 2-way binding doesn't work on array value, it needs some object to update

    So first change is let i = index; and [(ngModel)]="row[i]" :

    <td *ngFor="let cell of row; 
            let i = index;
            trackBy: customTrackBy
            ">
        <input type="text" class="form-control border-input" [(ngModel)]="row[i]" name="cell" />
    </td>
    

    Second Change : (Issue is shown in demo)

    // Your list will be reloaded again by ngFor when you change one field value, 
    // and it will lose the focus. 
    // You can add a trackBy to determine if the list must or must not be reloaded. The code below seems to solve the issue:
    
    customTrackBy(index: number, obj: any): any {
        return index;
    }
    

    WORKING DEMO ( With Solution + Issue )