Skip to content

Commit

Permalink
feat(select): add compareWith Input for object value comparison (#11965)
Browse files Browse the repository at this point in the history
fixes #6625
  • Loading branch information
zakton5 authored and manucorporat committed Jun 15, 2017
1 parent 2743c63 commit c7645ee
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 1 deletion.
14 changes: 14 additions & 0 deletions demos/src/select/pages/page-one/page-one.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
</ion-select>
</ion-item>

<ion-item>
<ion-label>Hair Color</ion-label>
<ion-select [(ngModel)]="hairColor" okText="Okay" cancelText="Dismiss" [compareWith]="compareFn">
<ion-option *ngFor="let o of hairColorData" [value]="o">{{o.text}}</ion-option>
</ion-select>
</ion-item>

<ion-item>
<ion-label>Gaming</ion-label>
<ion-select [(ngModel)]="gaming" okText="Okay" cancelText="Dismiss">
Expand Down Expand Up @@ -147,6 +154,13 @@
</ion-select>
</ion-item>

<ion-item>
<ion-label>Skittles</ion-label>
<ion-select [(ngModel)]="skittles" multiple="true" okText="Okay" cancelText="Dismiss" [compareWith]="compareFn">
<ion-option *ngFor="let o of skittlesData" [value]="o">{{o.text}}</ion-option>
</ion-select>
</ion-item>

<ion-item>
<ion-label>Disabled</ion-label>
<ion-select multiple disabled="true">
Expand Down
32 changes: 32 additions & 0 deletions demos/src/select/pages/page-one/page-one.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export class PageOne {
petAlertOpts: any;
petData: any;
pets: Array<string>;
hairColorData: any;
hairColor: any;
skittlesData: any;
skittles: Array<any>;
notifications: string = 'mute_1';
rating: number = 2;

Expand All @@ -31,9 +35,37 @@ export class PageOne {
{ text: 'Honey Badger', value: 'honeybadger' },
];

this.hairColorData = [
{ text: 'Brown', value: 'brown' },
{ text: 'Blonde', value: 'blonde' },
{ text: 'Black', value: 'black' },
{ text: 'Red', value: 'red' }
];

// Pre-selected object with different object reference
this.hairColor = { text: 'Brown', value: 'brown' };

this.skittlesData = [
{ text: 'Red', value: 'red' },
{ text: 'Orange', value: 'orange' },
{ text: 'Yellow', value: 'yellow' },
{ text: 'Green', value: 'green' },
{ text: 'Purple', value: 'purple' }
];

// Pre-selected object with different object reference
this.skittles = [
{ text: 'Red', value: 'red' },
{ text: 'Purple', value: 'purple' }
];

this.pets = ['cat', 'dog'];
}

compareFn(option1: any, option2: any) {
return option1.value === option2.value;
}

monthChange(val: any) {
console.log('Month Change:', val);
}
Expand Down
40 changes: 39 additions & 1 deletion src/components/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,31 @@ import { SelectPopover, SelectPopoverOption } from './select-popover-component';
* };
* ```
*
* ### Object Value References
*
* When using objects for select values, it is possible for the identities of these objects to
* change if they are coming from a server or database, while the selected value's identity
* remains the same. For example, this can occur when an existing record with the desired object value
* is loaded into the select, but the newly retrieved select options now have different identities. This will
* result in the select appearing to have no value at all, even though the original selection in still intact.
*
* Using the `compareWith` `Input` is the solution to this problem
*
* ```html
* <ion-item>
* <ion-label>Employee</ion-label>
* <ion-select [(ngModel)]="employee" [compareWith]="compareFn">
* <ion-option *ngFor="let employee of employees" [value]="employee">{{employee.name}}</ion-option>
* </ion-select>
* </ion-item>
* ```
*
* ```ts
* compareFn(e1: Employee, e2: Employee): boolean {
* return e1 && e2 ? e1.id === e2.id : e1 === e2;
* }
* ```
*
* @demo /docs/demos/src/select/
*/
@Component({
Expand Down Expand Up @@ -153,6 +178,7 @@ export class Select extends BaseInput<any> implements OnDestroy {
_overlay: ActionSheet | Alert | Popover;
_texts: string[] = [];
_text: string = '';
_compareWith: (o1: any, o2: any) => boolean = isCheckedProperty;

/**
* @input {string} The text to display on the cancel button. Default: `Cancel`.
Expand Down Expand Up @@ -187,6 +213,18 @@ export class Select extends BaseInput<any> implements OnDestroy {
*/
@Input() selectedText: string = '';

/**
* @input {Function} The function that will be called to compare object values
*/
@Input()
set compareWith(fn: (o1: any, o2: any) => boolean) {
if (typeof fn !== 'function') {
throw new Error(`compareWith must be a function, but received ${JSON.stringify(fn)}`);
}
this._compareWith = fn;
}


/**
* @output {any} Emitted when the selection was cancelled.
*/
Expand Down Expand Up @@ -448,7 +486,7 @@ export class Select extends BaseInput<any> implements OnDestroy {
this._options.forEach(option => {
// check this option if the option's value is in the values array
option.selected = this.getValues().some(selectValue => {
return isCheckedProperty(selectValue, option.value);
return this._compareWith(selectValue, option.value);
});

if (option.selected) {
Expand Down

0 comments on commit c7645ee

Please sign in to comment.