Angular 2 ngModel change of select box not updating selected option

Scot picture Scot · Dec 15, 2016 · Viewed 7.1k times · Source

I may or may not have found a bug in Angular 2. Basically what I'm trying to do is create a list of selected items of options chosen from a select box and when an item is selected it creates a new empty select box below the previous one so the user can continuously add selected items.

So what I want to do is reset the bottom select box back to an empty value, however when I try to set the ngModel value back to 0 (or empty) it still keeps the bottom select box at the previously selected option.

@Component({
    selector: 'my-app',
    template: `
    <div *ngFor="let a of arr">
        <div *ngFor="let b of a.entities;let i = index">
            <select class="form-control input-sm" [(ngModel)]="a.entities[i]">
                <option *ngFor="let c of items" value="{{c}}">{{c}}</option>
            </select>
        </div>
        <select class="form-control input-sm mb5" (change)="entitySelect(a)" [(ngModel)]="a.selected">
            <option value="0">- Select -</option>
            <option *ngFor="let c of items" value="{{c}}">{{c}}</option>
        </select>
    </div>
    `,
})
export class App {
    items:Array<string> = ['red','green','blue'];
    constructor() {
        this.arr = [{
            entities: [],
            selected: 0
        }]
     }
     entitySelect(entity) {
         entity.entities.push(entity.selected);
         entity.selected = 0; // Revert bottom select box back to empty
     }
}

https://plnkr.co/edit/PMzbgEtyd4DFhObu1UVz

The other odd thing is if I set entity.selected to say 'blue' instead of 0, then it will default the last select box to blue, but only on the first selection. Any selection after that it stays the same as the previous one.

https://plnkr.co/edit/Ze5uS1JjAmI7QXjQ17kQ

Answer

A. Tim picture A. Tim · Dec 15, 2016

It is very bad idea to use 2 way databinding ([(ngModel)]) with (change) event as you cannot predict/Angular cannot control what action will be handled first. So you have to rewrite your entitySelect function to manually assign value to entity\a. Second point has exact same reasons... Example that works for me:

@Component({
selector: 'my-app',
template: `
    <div *ngFor="let a of arr">
        <div *ngFor="let b of a.entities;let i = index">
            <select class="form-control input-sm" [(ngModel)]="a.entities[i]">
                <option *ngFor="let c of items" value="{{c}}">{{c}}</option>
            </select>
        </div>
        <select class="form-control input-sm mb5" (change)="entitySelect($event, a)" [ngModel]="a.selected">
            <option value="0">- Select -</option>
            <option *ngFor="let c of items" value="{{c}}">{{c}}</option>
        </select>
    </div>
`,
})
export class App {
    name:string;
    items:Array<string> = ['red','green','blue'];
    constructor() {
        this.name = 'Angular2'
        this.arr = [{
            entities: [],
            selected: 0
        }]
    }
    entitySelect($event, entity) {
        entity.entities.push($event.target.value);
        $event.target.value = 0;
    }
}