2

The picture below shows my table where the data is dynamically set. E.g., it could have 2,3,4 ... columns.

enter image description here

My html code is below: <thead> contains the title values, and tbody contains the values that can be modified.

<table class="table-conf">
    <thead>
       <tr>
           <th *ngFor="let data of jsonText[0]" style="text-align: center;">{{data}}</th>
       </tr>
    </thead>
    <tbody>
       <tr *ngFor="let data of jsonText; let i=index">
         <ng-container *ngIf="i!=0">
             <td class="padding-table" *ngFor="let dt of data; let j=index">
                 <input style="text-align: center;" [(ngModel)]="jsonText[i][j]">
             </td>
         </ng-container>
       </tr>
    </tbody>
</table>

Below is an example of jsonText variable that I iterated:

jsonText Array(6)
     0: (2) ["Task", "Hours per Day"]
     1: (2) ["Work", 11]
     2: (2) ["Eat", 2]
     3: (2) ["Commute", 2]
     4: (2) ["Watch TV", 2]
     5: (2) ["Sleep", 7]

The issue is: when I try to modify an element in the table, I can modify just one character at a time. For example: If I want to change "Eat" to "Lunch", I need to delete "Eat", then write L, click again on the input, write u, click again, etc...

Could anyone help me, please?

Patrick
  • 1,717
  • 7
  • 21
  • 28
Vítor Resende
  • 230
  • 3
  • 16
  • Does this answer your question? [Angular2 Dynamic input field lose focus when input changes](https://stackoverflow.com/questions/42322968/angular2-dynamic-input-field-lose-focus-when-input-changes) – user227353 Dec 02 '21 at 20:14

2 Answers2

8

As correctly said in other answer, When you bind jsonText to ngModel then ngFor re-evaluate and you lose focus out of input.

and when you do [(ngModel)]="dt" then ngModel can't bind to dynamically created variable. So you face this issue.

So to make it work:

(a) you have to apply trackBy function to your ngFor, Read

So in HTML add trackBy function, and do binding as [(ngModel)]="data[j] , Like :

 <tr *ngFor="let data of jsonText; let i=index">
         <ng-container *ngIf="i!=0">
             <td class="padding-table" *ngFor="let dt of data; let j=index; trackBy:customTrackBy">
                 <input style="text-align: center;" [(ngModel)]="data[j]">
             </td>
         </ng-container>
</tr>

(b) and in your component add the function and track the index.

     customTrackBy(index: number, obj: any): any {
         return index;
     }
anoop
  • 3,812
  • 2
  • 16
  • 28
1

Your ngFor is binding to jsonText, so every time you edit jsonText[i][j], you're forcing the ngFor directive to re-evaluate, which is why you lose focus.

In this case, just bind directly to 'dt'

 <input style="text-align: center;" [(ngModel)]="dt">

That way you're editing a field withing jsonText, not the entire object.

In addition, if dt isnt working in the model, then dt probably isnt what you expect it to be.

Add a line to your html template to display dt's value.

<tbody>
   <tr *ngFor="let data of jsonText; let i=index">
     <ng-container *ngIf="i!=0">
         <td class="padding-table" *ngFor="let dt.value of data; let j=index">
             {{dt.value | json}} // Add this
         </td>
     </ng-container>
   </tr>
</tbody>

Solution

The issue is with your json data. The jsonText array is just an array of an array of strings or numbers. Not 'objects', so they are not bound to any variable. Thats why ngModel doesn't work on 'dt'. dt isnt given a variable.

So, change how your jsonText array is setup to something like this:

jsonText = [
  [{ value: "task", id: 0}, {value: "Hours per day", id: 1}],
  [{ value: "work", id: 2}, {value: "11", id: 3}],
  [{ value: "eat", id: 4}, {value: "commute", id: 5}],
  ....
]

Working Example

Pezetter
  • 2,783
  • 2
  • 22
  • 40
  • Thank you for your answer. I've tried this on the beginning.But when I do this, I receive the follow message error: Uncaught Error: Cannot assign to a reference or variable! – Vítor Resende Apr 20 '18 at 13:55
  • I figured something would error, I'm not exactly sure how your jsonText array is setup. Check my updated answer to help debug. – Pezetter Apr 20 '18 at 13:56
  • I made what you've suggested and the result was what I've shown on the picture and it's the jsonText values: "Work", 1, "Eat", 2, "Commute", 2 ... – Vítor Resende Apr 20 '18 at 14:04
  • Thank you soo much for the answer. It helped me understand the situation and why it didn't work. Your solution really works but in my case I can't create an object due how the application with "jsonText" works, but your answers with @anoop answer solved my problem. Thank you so much!! – Vítor Resende Apr 20 '18 at 15:09
  • No problem. I had just remembered trackby. I'd go with that answer too! Cheers. – Pezetter Apr 20 '18 at 15:11