IonIcons in IonSelect:
The ion-select-option only returns strings however, all the Ion-Select technically does is show an interface that looks like a dropdown.
In short, what you can do, is, in this example, create a popover component that appears instead, of the normal dropdown by putting the dropdown in a clickable ion-item, disabling the dropdown, making it look enabled (for UX), clicking the dropdown when ion-item is clicked and then using that reference to open a popover component at that location.
So, there's some considerations I made when doing this:
I didn't want to recreate the dropdown box and icon, I only wanted to change what it displayed
I also wanted the icon to be clickable
Solution I ended up with (note this was also using ReactiveForms):
menu-options.interface.ts
export interface MenuOptions {
key: string;
fn: () => {};
}
MenuOptions will hold the value to display and the function to run when the button is pressed
main.component.ts
constructor(private cd: ChangeDetectorRef){}
menuOptions: MenuOptions[] = [
{
key: "Text",
fn: () =>
this._showAlert("Select this option if you want to type in values"),
},
{
key: "List",
fn: () =>
this._showAlert(
"Select this option if you want to use a pre-defined list of values"
),
},
{
key: "Textbox",
fn: () =>
this._showAlert(
"Select this option if you want an area to type a block of text"
),
},
];
// Find location of where popover is to appear and click the element
// which will then trigger the (click) event
onSelectionClick(event: any) {
let element: HTMLElement = document.getElementById('popoverLoc') as HTMLElement;
element.click();
}
async openPopover(event: any) {
const popover = await this.popover.create({
component: SelectionTypePopoverComponent,
componentProps: {
menuOptions: this.menuOptions
},
event,
translucent: true,
});
await popover.present();
const {data} = await popover.onWillDismiss();
// Get return from popover and set selection value
this.itemFeatureForm.get('selectionType').setValue(data['selectionType']);
// If you hardcode the menu options directly in the popover component and pass them back
// you will need to trigger change detection manually and set array to have 1 value
// otherwise your dropdown wont appear properly
// menuOptions: MenuOptions[] = [{ key: '', fn: () => '' }]
//this.cd.detectChanges();
}
main.component.html
<ion-item button (click)="onSelectionClick($event)" detail="false">
<ion-label class="enableItem">Selection Type</ion-label>
<ion-select
formControlName="selectionType"
class="enableItem"
id="popoverLoc"
(click)="openPopover($event)"
>
<ion-select-option
*ngFor="let option of menuOptions"
[value]="option.key"
>{{ option.key }}</ion-select-option
>
</ion-select>
</ion-item>
Wrap Ion-Label/Ion-Select in a clickable Ion-Item. This is going to be what registers the first click.
Make sure your ion-select is disabled: selectionType: new FormControl({value: '', disabled: true}),
enableItem class to make your Ion-Select look enabled: .enableItem {opacity: 1 !important;}
Set id to mark location of ion-select
popover.component.html
<ion-list>
<div *ngFor="let option of menuOptions; let i = index">
<ion-grid class="ion-no-padding">
<ion-row class="ion-no-padding">
<ion-col class="ion-no-padding">
<ion-item button detail="false" (click)="onSelection(i)">
<ion-label>{{ option.key }}</ion-label>
</ion-item>
</ion-col>
<ion-col class="ion-no-padding" size="2">
<ion-item class="ion-no-padding">
<ion-button class="ion-no-padding" fill="clear" (click)="onInfo(i)">
<ion-icon
name="information-circle-outline"
slot="icon-only"
></ion-icon>
</ion-button>
</ion-item>
</ion-col>
</ion-row>
</ion-grid>
</div>
</ion-list>
Make sure to set the size of the icon column
popover.component.ts
onSelection(index: number) {
this.popoverCtrl.dismiss({
selectionType: this.menuOptions[index].key,
});
}
onInfo(index: number) {
this.menuOptions[index].fn();
}
I've not done testing on physical devices yet but when I do, if this doesn't work, I will update but at the moment, with this pattern I can make whatever I want to appear in a dropdown and still using ionic templating...great power, responsibility and all that.