Ionic-framework: <ion-select> cannot select correct option if its values are objects, and ngModel is tied to a different object.

Created on 23 May 2016  路  16Comments  路  Source: ionic-team/ionic-framework

Short description of the problem:

cannot select the appropriate option if its values are objects, but the value tied to ngModel is another object with the same properties.

What behavior are you expecting?

I expect the correct option to be selected when the page loads, despite the fact that they are different objects with the same properties.

Assuming I have the following options tied to my ion-select:

options: any[] = [
        {
          key: 1,
          value: "test 1"
        },
        {
          key: 2,
          value: "test 2"
        },
        {
          key: 3,
          value: "test 3"
        },
      ];

and I assign the selected option like this:

this.selectedOption = this.options[1];      

It will correctly display the option. However, if I assign it like this (creating a new object with the same properties)

 this.selectedOption2 = {
          key: 3,
          value: "test 3"
        };

Then the ion-select will be blank

Suggestions:
The option to select is determined by a function that checks for exact equality (or object equality). Perhaps there should be an option that the user can pass in to the ion-select, something like trackBy, that will examine the object values' properties instead of the objects themselves.

Which Ionic Version?
2.x beta 6

Codepen

http://codepen.io/anon/pen/LNweqo

Run ionic info from terminal/cmd prompt: (paste output below)
Cordova CLI: 6.0.0
Gulp version: CLI version 3.9.0
Gulp local: Local version 3.9.1
Ionic Framework Version: 2.0.0-beta.6
Ionic CLI Version: 2.0.0-beta.25
Ionic App Lib Version: 2.0.0-beta.15
ios-deploy version: 1.8.4
ios-sim version: 5.0.6
OS: Mac OS X El Capitan
Node Version: v4.4.4
Xcode version: Xcode 7.3 Build version 7D175

Most helpful comment

This works for me.

Following the documentation linked above:
screen shot 2017-10-10 at 11 28 21 am

I made the following in component html:
screen shot 2017-10-10 at 11 29 46 am

And made the following function for comparing the different objects:
screen shot 2017-10-10 at 11 31 12 am

My ionic info is:
```cli packages:

@ionic/cli-utils  : 1.12.0
ionic (Ionic CLI) : 3.12.0

global packages:

cordova (Cordova CLI) : 7.0.1

local packages:

@ionic/app-scripts : 2.1.4
Cordova Platforms  : android 6.2.3 browser 4.1.0 ios 4.5.0
Ionic Framework    : ionic-angular 3.6.0

System:

Android SDK Tools : 25.2.5
ios-deploy        : 1.9.2
ios-sim           : 6.0.0
Node              : v6.9.4
npm               : 3.10.10
OS                : macOS Sierra
Xcode             : Xcode 9.0 Build version 9A235

Misc:

backend : pro```

All 16 comments

I've implemented a solution, and it seems to work properly, and I plan to submit a PR.

I've added an @Input() property that takes in a string value that represents the object property to compare. My only question is, what should I name it? As of now, it is called 'trackBy'. I could also call it 'property' or something like that. Any feedback?

I've already commented the below on the PR for this issue. I'm putting it here just for an update and a work around solution.

@cleever, angular does support this but not for my specific use case. I am pulling my pre-selected objects from a database. Therefore, the list of objects in my component, and the actual object used for the model value is a completely different object, even though it has the exact same properties.

I ended up doing this, which is similar to @xr0master's solution.

<ion-select [ngModel]="someProperty.id" (ngModelChange)="selectObjectById(list, $event, 'someProperty')">
    <ion-option *ngFor="let item of list" [value]="item.id">{{item.name}}</ion-option>
</ion-select>
public selectObjectById(list: any[], id: string, property: string) {
    var item = list.find(item => item._id === id);
    var prop = eval('this.' + property);
    prop = property;
}

This is essentially what the pull request did in the first place. It's unfortunate that this is necessary, but it works as desired.

I am currently experiencing the same issue. ion-select does not behave as expected when value is an object.

any updates on this?

The proper option does not get selected neither if the value is null:

<ion-select [ngModel]="category" (ngModelChange)="selectCategory($event)" name="category">
    <ion-option [value]="null">
        None
    </ion-option>
    <ion-option *ngFor="let category of categories | async" [value]="category">
        {{category}}
    </ion-option>
</ion-select>

If category is null I'd expect that the first option with None is selected, but neither options is selected.

This worked for me. The selected value is an object

<ion-item> <ion-label>*Select Units :&nbsp;</ion-label> <ion-select (ionChange)="unitSelectionChangeModal()" class="gsValidate gsSmallText" name="activeUnit" [(ngModel)]="activeUnit" required> <ion-option value=""></ion-option> <ion-option *ngFor="let item of activeSupportedUnits" [value]="item">{{item.abbrev}}</ion-option> </ion-select> </ion-item>

Hey ionic team @jgw96 @manucorporat ! This could be fixed by using Angular 4's new compareWith directive. Select API and compareWith
Those docs also explain well the problem that I have been trying to express this whole time.

I'm just going to make a PR for this and use the same logic as Angular's compareWith

I found the same problem. And if the data comes from a promise, it still has error about ngModel binding.

Why is it always impossible to get a response from the Ionic Team?

@granthoff1107 You can try compareWith directive to solve this problem. It works well. But I still didn't find a way to correctly use ion-select with the data from a promise.

<ion-select #country [(ngModel)]="countryData" > <ion-option *ngFor="let country of countries" value="{{stringify(country)}}" {{country.name}}</ion-option> </ion-select>

please note stringfiy is a function that just stringifies whole object. It may pose performance issue.

This works for me.

Following the documentation linked above:
screen shot 2017-10-10 at 11 28 21 am

I made the following in component html:
screen shot 2017-10-10 at 11 29 46 am

And made the following function for comparing the different objects:
screen shot 2017-10-10 at 11 31 12 am

My ionic info is:
```cli packages:

@ionic/cli-utils  : 1.12.0
ionic (Ionic CLI) : 3.12.0

global packages:

cordova (Cordova CLI) : 7.0.1

local packages:

@ionic/app-scripts : 2.1.4
Cordova Platforms  : android 6.2.3 browser 4.1.0 ios 4.5.0
Ionic Framework    : ionic-angular 3.6.0

System:

Android SDK Tools : 25.2.5
ios-deploy        : 1.9.2
ios-sim           : 6.0.0
Node              : v6.9.4
npm               : 3.10.10
OS                : macOS Sierra
Xcode             : Xcode 9.0 Build version 9A235

Misc:

backend : pro```

The above worked for me too. Thanks!

The above worked for me too even if I load in the options with an async pipe.

The above worked for me too! Angular/Ionic should have this built in.
Probably a [trackBy]="country.id" if using this example https://github.com/ionic-team/ionic/issues/6625#issuecomment-335325802

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SebastianGiro picture SebastianGiro  路  3Comments

brandyscarney picture brandyscarney  路  3Comments

GeorgeAnanthSoosai picture GeorgeAnanthSoosai  路  3Comments

masimplo picture masimplo  路  3Comments

fdnhkj picture fdnhkj  路  3Comments