1
votes

I have a form in angular. The form consists of a ngFor with a several selects.

<div *ngFor="let item of items; let i = index">
  <select name="" id="" [(ngModel)]="items[i]">
    <option *ngFor="let option of options" [value]="option.value">{{option.display}}</option>
  </select>
</div>

And the data for this example:

options = Array(10).fill(1).map((option,index) => {
    return {
      display:'thing' + index,
      value: index
    };
  });
  items = [2,7,2,7,2,7,2,7];

The strange thing is that when I change the 2nd select the 4th select will reflect the same change. However the model will not reflect this change.

For what ever reason the view will change the the input 2 indexes after it to match. Even stranger this will only happen the first time then it will behave how you would expect.

Here's the plunker to see the problem : http://plnkr.co/edit/q1YnoPBFdBKm0JDMVk7Q?p=preview

What would be causing this? How do I fix this issue?

1
Good question. Use trackBy to solve it. stackoverflow.com/questions/44476677/… Here's your example plnkr.co/edit/TAbQFqa3NeBvQ3FpKYCP?p=previewyurzui

1 Answers

1
votes

@yurzui had the right answer trackBy prevents any unnecessary mutations. Here is the code with the trackBy:

<div *ngFor="let item of items; let i = index; trackBy: trackByFn">
  <select name="" id="" [(ngModel)]="items[i]">
    <option *ngFor="let option of options" [value]="option.value">{{option.display}}</option>
  </select>
</div>

It's important for trackBy to take a function, which was one of my errors in solving this:

trackByFn(i: number) {
    return i;
  }

Working example provider by @yurzui:

https://plnkr.co/edit/TAbQFqa3NeBvQ3FpKYCP?p=preview