I have a parent component that generates some child components inside ngFor
:
<app-test-child *ngFor="let size of model.sizes; let i = index" [model]="model" [lineNumber]="i">
</app-test-child>
The model contains an array of sizes:
export class TestModel {
constructor(type: string) {
this.type = type;
this.sizes = new Array<number>();
}
type: string;
sizes: Array<number>;
}
What I'm trying to do is get each child component to update one size in the model. The child component currently looks something like this:
Item {{lineNumber + 1}}:
<select #radSize="ngModel" [(ngModel)]="model.sizes[lineNumber]">
<option *ngFor="let size of availableItems" [ngValue]="size" [selected]="size === model.sizes[lineNumber]">{{size}}
</option>
</select>
<br>
...where availableItems
is a simple array of numbers.
Here's a demo of the code above.
Problem:
If I select, say, the first item, the second item also updates and gets the focus. Actually, the ng-reflect-model
value only updates for the first item, not the second, so it's just a visual issue, but very confusing for users.
Any ideas what's causing this to happen?
UPDATE
It seems that the real issue is due to the fact that ngModel
is being bound to primitive values. According to this answer, that doesn't work very well.
The solution is to track the array by index. I've updated my demo, and it works perfectly!
Specifically, I added the following method to the parent component:
trackByIdx(index: number, obj: any): any {
return index;
}
Then updated my template as follows:
<app-test-child *ngFor="let size of model.sizes; let i = index; trackBy:trackByIdx" [model]="model" [lineNumber]="i">
</app-test-child>