mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 04:14:21 +08:00
177 lines
4.5 KiB
TypeScript
177 lines
4.5 KiB
TypeScript
import { Component, ComponentInterface, Host, Listen, Prop, h } from '@stencil/core';
|
|
|
|
import { getIonMode } from '../../global/ionic-global';
|
|
import { SelectPopoverOption } from '../../interface';
|
|
import { safeCall } from '../../utils/overlays';
|
|
import { getClassMap } from '../../utils/theme';
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
@Component({
|
|
tag: 'ion-select-popover',
|
|
styleUrls: {
|
|
ios: 'select-popover.ios.scss',
|
|
md: 'select-popover.md.scss'
|
|
},
|
|
scoped: true
|
|
})
|
|
export class SelectPopover implements ComponentInterface {
|
|
/**
|
|
* The header text of the popover
|
|
*/
|
|
@Prop() header?: string;
|
|
|
|
/**
|
|
* The subheader text of the popover
|
|
*/
|
|
@Prop() subHeader?: string;
|
|
|
|
/**
|
|
* The text content of the popover body
|
|
*/
|
|
@Prop() message?: string;
|
|
|
|
/**
|
|
* If true, the select accepts multiple values
|
|
*/
|
|
@Prop() multiple?: boolean;
|
|
|
|
/**
|
|
* An array of options for the popover
|
|
*/
|
|
@Prop() options: SelectPopoverOption[] = [];
|
|
|
|
@Listen('ionChange')
|
|
onSelect(ev: any) {
|
|
this.setChecked(ev);
|
|
this.callOptionHandler(ev);
|
|
}
|
|
|
|
private findOptionFromEvent(ev: any) {
|
|
const { options } = this;
|
|
return options.find(o => o.value === ev.target.value);
|
|
}
|
|
|
|
/**
|
|
* When an option is selected we need to get the value(s)
|
|
* of the selected option(s) and return it in the option
|
|
* handler
|
|
*/
|
|
private callOptionHandler(ev: any) {
|
|
const option = this.findOptionFromEvent(ev);
|
|
const values = this.getValues(ev);
|
|
|
|
if (option && option.handler) {
|
|
safeCall(option.handler, values);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is required when selecting a radio that is already
|
|
* selected because it will not trigger the ionChange event
|
|
* but we still want to close the popover
|
|
*/
|
|
private rbClick(ev: any) {
|
|
this.callOptionHandler(ev);
|
|
}
|
|
|
|
private setChecked(ev: any): void {
|
|
const { multiple } = this;
|
|
const option = this.findOptionFromEvent(ev);
|
|
|
|
// this is a popover with checkboxes (multiple value select)
|
|
// we need to set the checked value for this option
|
|
if (multiple && option) {
|
|
option.checked = ev.detail.checked;
|
|
}
|
|
}
|
|
|
|
private getValues(ev: any): any | any[] | null {
|
|
const { multiple, options } = this;
|
|
|
|
if (multiple) {
|
|
// this is a popover with checkboxes (multiple value select)
|
|
// return an array of all the checked values
|
|
return options.filter(o => o.checked).map(o => o.value);
|
|
}
|
|
|
|
// this is a popover with radio buttons (single value select)
|
|
// return the value that was clicked, otherwise undefined
|
|
const option = this.findOptionFromEvent(ev);
|
|
return option ? option.value : undefined;
|
|
}
|
|
|
|
renderOptions(options: SelectPopoverOption[]) {
|
|
const { multiple } = this;
|
|
|
|
switch (multiple) {
|
|
case true: return this.renderCheckboxOptions(options);
|
|
default: return this.renderRadioOptions(options);
|
|
}
|
|
}
|
|
|
|
renderCheckboxOptions(options: SelectPopoverOption[]) {
|
|
return (
|
|
options.map(option =>
|
|
<ion-item class={getClassMap(option.cssClass)}>
|
|
<ion-checkbox
|
|
slot="start"
|
|
value={option.value}
|
|
disabled={option.disabled}
|
|
checked={option.checked}
|
|
>
|
|
</ion-checkbox>
|
|
<ion-label>
|
|
{option.text}
|
|
</ion-label>
|
|
</ion-item>
|
|
)
|
|
)
|
|
}
|
|
|
|
renderRadioOptions(options: SelectPopoverOption[]) {
|
|
const checked = options.filter(o => o.checked).map(o => o.value)[0];
|
|
|
|
return (
|
|
<ion-radio-group value={checked}>
|
|
{options.map(option =>
|
|
<ion-item class={getClassMap(option.cssClass)}>
|
|
<ion-label>
|
|
{option.text}
|
|
</ion-label>
|
|
<ion-radio
|
|
value={option.value}
|
|
disabled={option.disabled}
|
|
onClick={ev => this.rbClick(ev)}
|
|
>
|
|
</ion-radio>
|
|
</ion-item>
|
|
)}
|
|
</ion-radio-group>
|
|
)
|
|
}
|
|
|
|
render() {
|
|
const { header, message, options, subHeader } = this;
|
|
const hasSubHeaderOrMessage = subHeader !== undefined || message !== undefined;
|
|
|
|
return (
|
|
<Host class={getIonMode(this)}>
|
|
<ion-list>
|
|
{header !== undefined && <ion-list-header>{header}</ion-list-header>}
|
|
{ hasSubHeaderOrMessage &&
|
|
<ion-item>
|
|
<ion-label class="ion-text-wrap">
|
|
{subHeader !== undefined && <h3>{subHeader}</h3>}
|
|
{message !== undefined && <p>{message}</p>}
|
|
</ion-label>
|
|
</ion-item>
|
|
}
|
|
{this.renderOptions(options)}
|
|
</ion-list>
|
|
</Host>
|
|
);
|
|
}
|
|
}
|