I am facing issue with ion-select(array objects) (multiple select). Two items are already selected on page load, but when you open the drop-down, none of the items are checked. Here is stackblitz link to reproduce this issue.
https://stackblitz.com/edit/ionic-angular-v5-kie1wd
I am using Ionic(5.26.0) and angular(8.2.14) for my project.
<ion-item>
<ion-label>Users(Multi)</ion-label>
<ion-select multiple="true" [(ngModel)]="selectedMultipleEmployee" [compareWith]="compareFn"
(ionChange)="multiChange()">
<ion-select-option *ngFor="let user of users" [value]="user">{{user.first + ' ' + user.last}}
</ion-select-option>
</ion-select>
</ion-item>
compareFn(e1: User, e2: User): boolean {
return e1 && e2 ? e1.id === e2.id : e1 === e2;
}
Your compareWith(e1, e2)
function must return true
if e2
is an array and a single element e1
is in e2
, for example:
// defined outside of class
const compareWith = (e1, e2) => {
// e2 may be an array, if multiple="true"
if (Array.isArray(e2) ) {
return e2.indexOf(e1) !== -1;
}
// fallback to single element comparison
return e1 && e2 ? e1.id === e2.id : e1 === e2;
}
class MyPage {
...
compareFn = compareWith;
...
}
Important: also, define your function compareWith
outside of the class, otherwise it does not work
I've had the same issue after upgrading from Ionic3 to Ionic5, and I've debugged the ion-select
code to see what's causing this issue.
Here's the function that determines if the an option must be checked or unchecked:
const compareOptions = (currentValue, compareValue, compareWith) => {
if (typeof compareWith === 'function') {
return compareWith(currentValue, compareValue);
}
else if (typeof compareWith === 'string') {
return currentValue[compareWith] === compareValue[compareWith];
}
else {
return Array.isArray(compareValue) ? compareValue.includes(currentValue) : currentValue === compareValue;
}
};
The compareValue
is an array and the final else
clause handles that case if compareWith
is not provided. But since you provide your own compareWith
function, then it has to be able to check if a single items belongs to that array.
Here's the actual code that worked for my specific case (comparing items by field code
):
const compareWith = (f1, f2) => {
if (Array.isArray(f2)) {
if (!f1 || !f1.code) {
return false;
}
return f2.find(val => val && val.code === f1.code);
}
return f1 && f2 ? f1.code === f2.code : f1 === f2;
};
Update: Added a note that compareWith
needs to be defined outside of the class.