Pengyy
Pengyy

Reputation: 38171

Angular: selected on option of select doesn't work as excepted while using along with ngModel

I have an array of objects(named users) which will be shown as options of dropdownlist. and I have another objects list(named selectedUsers and is saved in backend) which is used to initialize the dropdownlist.

array:

users = [
  {
    id: 2,
    name: 'name2'
  },{
    id: 2,
    name: 'name2'
  },{
    id: 3,
    name: 'name3'
  }
];

selectedUsers3 = [
  {
    id: 1,
    name: 'name1'
  },{
    id: 2,
    name: 'name2'
  }
];

I'm facing a wired situation which is when I bind Object to select options by [ngValue], and bind a function to [selected] which will check whether the current option exists in selectedUsers.

I can see the function is retrieved and the result is returned true/false as excepted, but the options keeps unselected.

template:

<select multiple [(ngModel)]="selectedUsers3">
  <option *ngFor="let user of users" [selected]="checkExist(user)" [ngValue]="user">{{user.name}}</option>
</select>

function in component:

checkExist(user) {
  return this.selectedUsers3.findIndex(selUser => selUser.id === user.id) > -1;
  //return this.selectedUsers3.filter(selUser => selUser.id === user.id).length > 0;
}

mention that I used Array.filter or Array.findIndex to check whether the data exists, and the result is correct.

Please refer this demo with the third dropdownlist, and check where am I doing something wrong? or am I missing something about [selected]? I hope someone can explain clearly about this.

UPD:

with @Günter Zöchbauer's help, this situation can be solved by using compareWith directive(refer his answer) no matter single select or multi select, but I'm still confused why they work well alongside but fail together and still trying to figure out the reason.

Upvotes: 3

Views: 7102

Answers (2)

Pengyy
Pengyy

Reputation: 38171

Answer to conflicts between [(ngModel)] and [selected]

after some research and debug, I find that while using ngModel on select, angular will run it's own SelectMultipleControlValueAccessor for select and own directive for option of select which lead selected to be ignored.

In the third example(example plunker), after ngModel is used, although function bind to [selected] will be called, but it's result is simply ignored.


Comments

  • comment1:
    The problem can be solved by binding [(ngModel)] and [ngValue] with same instance of objects.
  • comment2:
    The problem can also be solved by using compareWith directive, see Gunter' s anwser
  • comment3:
    This will happen also for single select, see SelectControlValueAccessor and directive for option.

New Info:

See also this issue for more information.

Upvotes: 1

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657158

selected is not supported with [(ngModel)]="selectedUser3".

To make an item selected, the value (for string only) or ngValue property value needs to match the value in selectedUser3.

this.selectedUser3 = this.users[2];

By default only object identity is checked, therefore another object instance with the same properties and values doesn't match. You can customize comparison using compareWith

https://angular.io/docs/ts/latest/api/forms/index/SelectControlValueAccessor-directive.html

<select [compareWith]="compareFn"  [(ngModel)]="selectedCountries">
    <option *ngFor="let country of countries" [ngValue]="country">
        {{country.name}}
    </option>
</select>
compareFn(c1: Country, c2: Country): boolean {
    return c1 && c2 ? c1.id === c2.id : c1 === c2;
}

Upvotes: 8

Related Questions