Ionic version:
[x] 4.9.0
Current behavior:
If ion-select-options are passed with a delay, the selected property is not respected.
This happens e.g. if you get the options via http request.
Expected behavior:
The selected binding should work, with or without, the delay.
Steps to reproduce:
See stackblitz.
Related code:
https://stackblitz.com/edit/ionic-v4-angular-tabs-ecdgvr?file=src%2Fapp%2Fhome%2Fhome.page.ts
Thanks for the issue. Please try this again using compareWith https://ionicframework.com/docs/api/select#object-value-references.
Thanks for the tip. I modified the stackblitz. Using compareWith the value is selected, but the ion-select is not rendered correctly. That means the selected value isn't shown, till the select is clicked.
https://stackblitz.com/edit/ionic-v4-angular-tabs-ecdgvr?file=src%2Fapp%2Fhome%2Fhome.page.ts
I'm having the exact same problem with Ionic 4.9.1. 4.7.x and 4.8.x didn't had that issue.
Exact same issue too with Ionic 4.10.0-dev.201909261535.8ca97ce
On 4.10.1 the issue is still there. Issue #19436 sounds similar.
I think I found the problem.
@liamdebeasi, why the functionality of the file select.tsx in the line 135 to 157 was removed? It was remove from 4.8.1 to 4.9.1.
https://github.com/ionic-team/ionic/commit/48a27636c76c1a05dc6d878be26cbe028552cbf7#diff-e954ed7de7ce8c631442335752663627
It seems like it was the responsible of detect changes inside the DOM of select component.
Maybe I can't see by which other functionality it was replaced, please, can you help us?
I hope I provided you enough information.
@Listen('ionSelectOptionDidLoad')
@Listen('ionSelectOptionDidUnload')
async selectOptionChanged() {
await this.loadOptions();
if (this.didInit) {
this.updateOptions();
this.updateOverlayOptions();
this.emitStyle();
/**
* In the event that options
* are not loaded at component load
* this ensures that any value that is
* set is properly rendered once
* options have been loaded
*/
if (this.value !== undefined) {
this.el.forceUpdate();
}
}
}
Issue #19828 looks similar.
Any updates from Ionic-Team on this matter?
Thanks for the follow up. I've marked this as a bug. The select component was updated to fix a few other bugs, but it looks like this functionality broke in the process. I will look into an appropriate fix for this and will post an update here when I have more to share. Thanks!
@liamdebeasi Any update on this matter?
Hi there,
i too ran into this issue and was struggeling for two days.
Sadly the made fix mentioned in similar issue #17225 is not solving the problem for Ionic 4 (@ionic/core 4.11.5)!
The issue is easy to reproduce with the following steps:
ReactiveFormsModule to imports within home.module.tsion-content within home.page.html:```
home.page.ts with:```
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
public formData: FormGroup;
public Items: Array<{
value: string,
text: string
}> = [];
constructor(formBuilder: FormBuilder) {
this.formData = formBuilder.group({
selectedItem: ''
});
}
private async demonstrateAsyncLoadingIssue() {
this.Items = await new Promise<any>((resolve) => {
// commect out setTimeout and resolve directly
// to proof select ui gets updated correctly without delay
setTimeout(() => {
resolve([
{
value: 'sucks',
text: 'Damnit, this sucks :('
},
{
value: 'works',
text: 'Aww yeah, it works :)'
}
]);
}, 500);
});
this.formData.patchValue({ selectedItem: 'sucks' });
}
ngOnInit() {
this.demonstrateAsyncLoadingIssue();
}
}
```
run ionic serve and observe that text in ion-input gets updated after 500ms but the selected item is not. If you click on the select control, you see that the value was set correctly and is displayed/selected. (i didn't include it in this example, but you can subscribe to formControl valueChanges Observable and see that the value is set correctly; also ionChange event on ion-select fires too, but UI does not update)
you can proof that UI is updating correctly without delayed Promise by commenting setTimeout and directly resolve the data.
As for now the only working solutions to this are
*ngIf="Items && Items.length" to ion-select. In this case evaluating ngIf seems to bypass the problem by re-rendering the control.ChangedetectorRef and doing a manual detectChanges() after patching formgroup, but this feels kind of fishy :confused: Very annoying, hopefully we see a fix soon...
We are having the same problem with 4.11.6, demo here : https://angular-ionic-4-efei58.stackblitz.io/home
Second menu value is bound correctly, and if you open the menu the value is highlighted correctly, but it doesn't display.
Bug still exist with 5.0.x. I can confirm that adding *ngIf="items && items.length" to ion-select does bypass the problem.
This was a problem also on older versions as well, which was fixed previously and now it is back from a while.
We use ngx-formly and have created a merge request to workaround this problem
Bug still exist with 5.0.x. I can confirm that adding
*ngIf="items && items.length"toion-selectdoes bypass the problem.
How do you deal with this issue if you're using an observable to populate the select options? I had to resort to angular-material's mat-select to get this working.
Something like that
<ng-container *ngIf="to.options | async; let options">
<ion-select>
<ion-select-option *ngFor="let option of options" [value]="option.value">
{{ option.label }}
</ion-select-option>
</ion-select>
</ng-container>
a major bug still open after half a year. actually to fix it i think it would take just a few minutes. i think this is urgent, because forms just doesn't work. most of the time values are loaded async and boom it doesn't work.
however, this workaround works:
<ion-select *ngIf="(projects$ | async)?.length > 0" interface="popover"
[placeholder]="'Choose Project' | translate"
formControlName="projectId">
<ion-select-option *ngFor="let project of projects$ | async"
[value]="project.id">{{project.name || project.id}}</ion-select-option>
</ion-select>
@nickwinger If you have an idea for how to resolve the issue, would you be interested in making a PR for it? I'd be happy to review it.
@liamdebeasi Well i'm not into the internals of Ionic and how you do the angular wrapping since you moved to stencil, but i know that you implement the interface ControlValueAccessor in angular to be able to support formControlName. Then there are many options how to recognize if the children ion-select-options change. Vanilla DOM would be to make a MutationObserver.
So every time new ion-select-options appear, you look for the value and re-select it. The binding between the parent ion-select value and the ion-select-options children has to be there all the time of course...
You could also use angular's ViewChildrens maybe to detect changes in the ion-select-options array.
There are many ways to accomplish this, even the mutationobserver way, one of the simplest and most primitive of course, would be better than to have this bug, because i think this is really really urgent. You cannot use (async) forms at all (without the *ngIf workaround, which newcomers maybe dont know)
The error still seems to persist.
The only way around is to add an *ngIf to verify that the options are loaded:
<ion-select *ngIf="locationsList && locationsList.length" multiple
placeholder="Select locations"
formControlName="locations">
<ion-select-option *ngFor="let location of locationsList"
[value]="item.id">{{location.name}}</ion-select-option>
</ion-select>
Same issue when updating the value for a multi select
For those looking for a React solution:
You can wrap your value (in my case a number) in a fresh object each time and it will force the IonSelect to reselect every time it renders:
const compareWith = (curr, compar) => {return curr && compar? curr.id === compar.id: curr === compar;};
<IonSelect compareWith={compareWith} value={{id: mySelectValue}} onIonChange={e => setMySelectValue(e.detail.value!.id)}>
{mySelectOptions}
</IonSelect>
This allows you to use objects or anything else as values while also working properly if mySelectValue is set before mySelectOptions.
This worked for me
<ion-select interface="popover" [(ngModel)]="selected" (ionChange)="selected = $event.detail.value">
<ion-select-option *ngFor="let item of list" [value]="item.id">{{ item.text }}</ion-select-option>
</ion-select>
Most helpful comment
We are having the same problem with 4.11.6, demo here : https://angular-ionic-4-efei58.stackblitz.io/home
Second menu value is bound correctly, and if you open the menu the value is highlighted correctly, but it doesn't display.