3

I have a weird problem.

I am using Angular CLI and I have added Material 2 to it. I created some inputs with ngfor and bound them to ngmodel. Everything is working fine.

But whenever I type something, the input becomes deselected.

This is the HTML code of the component:

<md-input-container class="treatments" *ngFor="let t of treatment; let i = index">
    <input mdInput placeholder="treatment {{ i + 1 }}" 
      value="{{ t[i] }}" name="treatment_{{ i + 1 }}" [(ngModel)]="treatment[i]">
</md-input-container>

When I remove the ngmodel, it does work 100%.

FAISAL
  • 33,618
  • 10
  • 97
  • 105
  • Can you show how treatment looks like? – Nehal Jun 16 '17 at 19:35
  • @Nehal It looks like [ "treatment 1", "treatment 2", "etc..." ] Thats it ... ( not a relevent question - how i can change my name from the mobile version of stack overflow - ). Thanks – TheSnake620 Jun 16 '17 at 20:58
  • @TheSnake620 How did it ever go with either of the answers provided? :) – AT82 Jun 29 '17 at 11:27
  • @AJT_82 i have tested the second one with trackBy, amd deleted the value attr, and does work very will( if i did not delete the value attr it just write 2 letters and then any letter i wrrite it deletes the letter before it ), i will test the first answer later. – TheSnake620 Jun 29 '17 at 23:32

2 Answers2

3

You are iterating over an Array of primitive type, and thus they are compared by value. When you change a treatment (i.e t), all values are destroyed and new ones created, which causes the field to loose focus. This can be solved by using trackBy, which tracks the treatments by the index and only destroys and recreates the treatment you are modifying.

So add trackBy:

<md-input-container class="treatments" *ngFor="let t of treatment; 
    let i = index; trackBy:trackByFn">

and in TS add the function:

trackByFn(index, treatment) {
  return index;
}
AT82
  • 71,416
  • 24
  • 140
  • 167
0

The problem is you are trying to bind ngModel to primitive values. You can solve the deselect problem by adding @Input() before the treatment declaration.

@Input() treatment: string[] = [ "treatment 1", "treatment 2"];

But it will not update the values in the array. If you want the values to update, ngModel needs to bind with object property. I have added both examples in this Plnkr.

For more info, refer this SO question Angular2 ngModel inside of ngFor

Nehal
  • 13,130
  • 4
  • 43
  • 59
  • I really can't see why you mentioned `@Input` since the question isn't about passing data via components... Anyway, it's worth to mention that the `value="{{ t[i] }}"` is also a problem, it was conflicting with `ngModel` there. – developer033 Jun 17 '17 at 01:41
  • @Nehal Your Way didn't work, i have to use trackBy, BTW Thanks for your help :). – TheSnake620 Jun 30 '17 at 03:02