mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 11:17:19 +08:00
feat(select): get select component working with action sheet / popover
- adds markup for the select - gets placeholder working properly - adds select popover component - renames option to select-option - adds a function to get label text from item
This commit is contained in:
@ -120,8 +120,8 @@
|
||||
<ion-item>
|
||||
<ion-label>Gender</ion-label>
|
||||
<ion-select [(ngModel)]="login.gender" formControlName="gender">
|
||||
<ion-option value="f">Female</ion-option>
|
||||
<ion-option value="m">Male</ion-option>
|
||||
<ion-select-option value="f">Female</ion-select-option>
|
||||
<ion-select-option value="m">Male</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, Element, Prop, Listen } from '@stencil/core';
|
||||
import { Component, Element, HostElement, Method, Prop, Listen } from '@stencil/core';
|
||||
import { CssClassMap } from '../../index';
|
||||
import { createThemedClasses } from '../../utils/theme';
|
||||
|
||||
@ -13,6 +13,7 @@ import { createThemedClasses } from '../../utils/theme';
|
||||
})
|
||||
export class Item {
|
||||
private childStyles: CssClassMap = Object.create(null);
|
||||
private label: any;
|
||||
|
||||
@Element() private el: HTMLElement;
|
||||
|
||||
@ -38,12 +39,28 @@ export class Item {
|
||||
return hasChildStyleChange;
|
||||
}
|
||||
|
||||
@Method()
|
||||
getLabelText(): string {
|
||||
return this.label ? this.label.getText() : '';
|
||||
}
|
||||
|
||||
ionViewDidLoad() {
|
||||
// Add item-button classes to each ion-button in the item
|
||||
const buttons = this.el.querySelectorAll('ion-button') as any;
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
buttons[i].itemButton = true;
|
||||
}
|
||||
|
||||
this.label = this.el.querySelector('ion-label') as HostElement;
|
||||
|
||||
// if (label) {
|
||||
// this.label = label;
|
||||
// this.labelId = label.id = ('lbl-' + this.id);
|
||||
// if (label.type) {
|
||||
// this.setElementClass('item-label-' + label.type, true);
|
||||
// }
|
||||
// this.viewLabel = false;
|
||||
// }
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -168,12 +185,6 @@ export class Item {
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @hidden
|
||||
// */
|
||||
// getLabelText(): string {
|
||||
// return this._label ? this._label.text : '';
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @hidden
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, Event, EventEmitter, Prop } from '@stencil/core';
|
||||
import { Component, Element, Event, EventEmitter, Method, Prop } from '@stencil/core';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -15,6 +15,8 @@ import { Component, Event, EventEmitter, Prop } from '@stencil/core';
|
||||
export class Label {
|
||||
styleTmr: any;
|
||||
|
||||
@Element() el: HTMLElement;
|
||||
|
||||
/**
|
||||
* @output {event} Emitted when the styles change.
|
||||
*/
|
||||
@ -35,6 +37,14 @@ export class Label {
|
||||
*/
|
||||
@Prop() stacked: boolean = false;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
@Method()
|
||||
getText(): string {
|
||||
return this.el.textContent || '';
|
||||
}
|
||||
|
||||
ionViewDidLoad() {
|
||||
this.emitStyle();
|
||||
}
|
||||
|
39
packages/core/src/components/select-option/select-option.tsx
Normal file
39
packages/core/src/components/select-option/select-option.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { Component, Element, Event, EventEmitter, Method, Prop } from '@stencil/core';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-select-option',
|
||||
host: {
|
||||
theme: 'select-option'
|
||||
}
|
||||
})
|
||||
export class SelectOption {
|
||||
@Element() el: HTMLElement;
|
||||
|
||||
@Event() ionSelect: EventEmitter;
|
||||
|
||||
/**
|
||||
* @input {boolean} If true, the user cannot interact with this element.
|
||||
*/
|
||||
@Prop() disabled: boolean = false;
|
||||
|
||||
/**
|
||||
* @input {boolean} If true, the element is selected.
|
||||
*/
|
||||
@Prop() selected: boolean = false;
|
||||
|
||||
/**
|
||||
* @input {string} The text value of the option.
|
||||
*/
|
||||
@Prop() value: string;
|
||||
|
||||
@Method()
|
||||
getText(): string {
|
||||
return this.el.textContent || '';
|
||||
}
|
||||
|
||||
render() {
|
||||
return <slot></slot>;
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { Component } from '@stencil/core';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-option',
|
||||
host: {
|
||||
theme: 'option'
|
||||
}
|
||||
})
|
||||
export class option {
|
||||
|
||||
render() {
|
||||
return <div class="my-option"></div>;
|
||||
}
|
||||
|
||||
}
|
55
packages/core/src/components/select/select-popover.tsx
Normal file
55
packages/core/src/components/select/select-popover.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
import { Component, Prop, PropDidChange } from '@stencil/core';
|
||||
|
||||
export interface SelectPopoverOption {
|
||||
text: string;
|
||||
value: string;
|
||||
disabled: boolean;
|
||||
checked: boolean;
|
||||
handler?: Function;
|
||||
}
|
||||
|
||||
@Component({
|
||||
tag: 'ion-select-popover'
|
||||
})
|
||||
export class SelectPopover {
|
||||
@Prop() options: SelectPopoverOption[];
|
||||
|
||||
@Prop({ state: true }) value: string;
|
||||
|
||||
@PropDidChange('value')
|
||||
valueChanged(val: string) {
|
||||
console.log('Select popover value', val);
|
||||
}
|
||||
|
||||
// public get value() {
|
||||
// let checkedOption = this.options.find(option => option.checked);
|
||||
|
||||
// return checkedOption ? checkedOption.value : undefined;
|
||||
// }
|
||||
|
||||
// public set value(value: any) {
|
||||
// let checkedOption = this.options.find(option => option.value === value);
|
||||
// if (checkedOption && checkedOption.handler) {
|
||||
// checkedOption.handler();
|
||||
// }
|
||||
// this.viewController.dismiss(value);
|
||||
// }
|
||||
|
||||
render() {
|
||||
console.log(this.options);
|
||||
|
||||
return (
|
||||
<ion-list radio-group value="{this.value}">
|
||||
{this.options.map(option =>
|
||||
<ion-item>
|
||||
<ion-label>{option.text}</ion-label>
|
||||
<ion-radio checked={option.checked} value={option.value} disabled={option.disabled}></ion-radio>
|
||||
</ion-item>
|
||||
)}
|
||||
</ion-list>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@ $select-popover-list-margin-start: 0 !default;
|
||||
|
||||
|
||||
ion-select {
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
@ -51,6 +53,6 @@ ion-select {
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
.select .option {
|
||||
.select-option {
|
||||
display: none;
|
||||
}
|
@ -1,4 +1,14 @@
|
||||
import { Component, CssClassMap, Event, EventEmitter, Prop } from '@stencil/core';
|
||||
import { Component, CssClassMap, Element, Event, EventEmitter, HostElement, Prop } from '@stencil/core';
|
||||
|
||||
import { deepCopy } from '../../utils/helpers';
|
||||
|
||||
import { ActionSheet } from '../action-sheet/action-sheet';
|
||||
import { Alert } from '../alert/alert';
|
||||
import { Popover } from '../popover/popover';
|
||||
|
||||
import { ActionSheetController } from '../action-sheet-controller/action-sheet-controller';
|
||||
// import { AlertController } from '../alert-controller/alert-controller';
|
||||
import { PopoverController } from '../popover-controller/popover-controller';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -14,8 +24,18 @@ import { Component, CssClassMap, Event, EventEmitter, Prop } from '@stencil/core
|
||||
})
|
||||
export class Select {
|
||||
text: any;
|
||||
id: any;
|
||||
labelId: any;
|
||||
texts: any;
|
||||
id: string;
|
||||
labelId: string;
|
||||
item: any;
|
||||
options: any;
|
||||
overlay: ActionSheet | Alert | Popover;
|
||||
|
||||
@Prop({ connect: 'ion-action-sheet-controller' }) actionSheetCtrl: ActionSheetController;
|
||||
// @Prop({ connect: 'ion-alert-controller' }) alertCtrl: AlertController;
|
||||
@Prop({ connect: 'ion-popover-controller' }) popoverCtrl: PopoverController;
|
||||
|
||||
@Element() el: HTMLElement;
|
||||
|
||||
/**
|
||||
* @input {boolean} If true, the user cannot interact with this element. Defaults to `false`.
|
||||
@ -48,7 +68,7 @@ export class Select {
|
||||
/**
|
||||
* @input {string} The interface the select should use: `action-sheet`, `popover` or `alert`. Default: `alert`.
|
||||
*/
|
||||
@Prop() interface: string = '';
|
||||
@Prop() interface: string = 'alert';
|
||||
|
||||
/**
|
||||
* @input {string} The text to display instead of the selected option's value.
|
||||
@ -61,284 +81,9 @@ export class Select {
|
||||
@Prop() multiple: boolean;
|
||||
|
||||
/**
|
||||
* @output {EventEmitter} Emitted when the selection is cancelled.
|
||||
* @input {string} the value of the select.
|
||||
*/
|
||||
@Event() ionCancel: EventEmitter;
|
||||
|
||||
|
||||
hostData() {
|
||||
return {
|
||||
class: {
|
||||
'select-disabled': this.disabled
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let addPlaceholderClass = false
|
||||
|
||||
let selectText = this.selectedText || this.text;
|
||||
if (!selectText && this.placeholder) {
|
||||
selectText = this.placeholder;
|
||||
addPlaceholderClass = true;
|
||||
}
|
||||
|
||||
const selectTextClasses: CssClassMap = {
|
||||
'select-text': true,
|
||||
'select-placeholder': addPlaceholderClass
|
||||
};
|
||||
|
||||
return [
|
||||
// add placeholder class
|
||||
<div class={selectTextClasses}>{ selectText }</div>,
|
||||
<div class="select-icon">
|
||||
<div class="select-icon-inner"></div>
|
||||
</div>,
|
||||
<button
|
||||
aria-haspopup="true"
|
||||
id={this.id}
|
||||
aria-labelledby={this.labelId}
|
||||
aria-disabled={this.disabled ? "true" : false}
|
||||
class="item-cover">
|
||||
</button>
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// export class Select extends BaseInput<any> implements OnDestroy {
|
||||
|
||||
// _options: QueryList<Option>;
|
||||
// _overlay: ActionSheet | Alert | Popover;
|
||||
// _texts: string[] = [];
|
||||
// _text: string = '';
|
||||
|
||||
|
||||
// @HostListener('click', ['$event'])
|
||||
// _click(ev: UIEvent) {
|
||||
// if (ev.detail === 0) {
|
||||
// // do not continue if the click event came from a form submit
|
||||
// return;
|
||||
// }
|
||||
// ev.preventDefault();
|
||||
// ev.stopPropagation();
|
||||
// this.open(ev);
|
||||
// }
|
||||
|
||||
// @HostListener('keyup.space')
|
||||
// _keyup() {
|
||||
// this.open();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @hidden
|
||||
// */
|
||||
// getValues(): any[] {
|
||||
// const values = Array.isArray(this._value) ? this._value : [this._value];
|
||||
// assert(this._multi || values.length <= 1, 'single only can have one value');
|
||||
// return values;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Open the select interface.
|
||||
// */
|
||||
// open(ev?: UIEvent) {
|
||||
// if (this.isFocus() || this._disabled) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// console.debug('select, open alert');
|
||||
|
||||
// // the user may have assigned some options specifically for the alert
|
||||
// const selectOptions = deepCopy(this.selectOptions);
|
||||
|
||||
// // make sure their buttons array is removed from the options
|
||||
// // and we create a new array for the alert's two buttons
|
||||
// selectOptions.buttons = [{
|
||||
// text: this.cancelText,
|
||||
// role: 'cancel',
|
||||
// handler: () => {
|
||||
// this.ionCancel.emit(this);
|
||||
// }
|
||||
// }];
|
||||
|
||||
// // if the selectOptions didn't provide a title then use the label's text
|
||||
// if (!selectOptions.title && this._item) {
|
||||
// selectOptions.title = this._item.getLabelText();
|
||||
// }
|
||||
|
||||
// let options = this._options.toArray();
|
||||
// if (this.interface === 'action-sheet' && options.length > 6) {
|
||||
// console.warn('Interface cannot be "action-sheet" with more than 6 options. Using the "alert" interface.');
|
||||
// this.interface = 'alert';
|
||||
// }
|
||||
|
||||
// if ((this.interface === 'action-sheet' || this.interface === 'popover') && this._multi) {
|
||||
// console.warn('Interface cannot be "' + this.interface + '" with a multi-value select. Using the "alert" interface.');
|
||||
// this.interface = 'alert';
|
||||
// }
|
||||
|
||||
// if (this.interface === 'popover' && !ev) {
|
||||
// console.warn('Interface cannot be "popover" without UIEvent.');
|
||||
// this.interface = 'alert';
|
||||
// }
|
||||
|
||||
// let overlay: ActionSheet | Alert | Popover;
|
||||
|
||||
// if (this.interface === 'action-sheet') {
|
||||
// selectOptions.buttons = selectOptions.buttons.concat(options.map(input => {
|
||||
// return {
|
||||
// role: (input.selected ? 'selected' : ''),
|
||||
// text: input.text,
|
||||
// handler: () => {
|
||||
// this.value = input.value;
|
||||
// input.ionSelect.emit(input.value);
|
||||
// }
|
||||
// };
|
||||
// }));
|
||||
// var selectCssClass = 'select-action-sheet';
|
||||
|
||||
// // If the user passed a cssClass for the select, add it
|
||||
// selectCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
|
||||
|
||||
// selectOptions.cssClass = selectCssClass;
|
||||
// overlay = new ActionSheet(this._app, selectOptions, this.config);
|
||||
|
||||
// } else if (this.interface === 'popover') {
|
||||
// let popoverOptions: SelectPopoverOption[] = options.map(input => ({
|
||||
// text: input.text,
|
||||
// checked: input.selected,
|
||||
// disabled: input.disabled,
|
||||
// value: input.value,
|
||||
// handler: () => {
|
||||
// this.value = input.value;
|
||||
// input.ionSelect.emit(input.value);
|
||||
// }
|
||||
// }));
|
||||
|
||||
// var popoverCssClass = 'select-popover';
|
||||
|
||||
// // If the user passed a cssClass for the select, add it
|
||||
// popoverCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
|
||||
|
||||
// overlay = new Popover(this._app, SelectPopover, {
|
||||
// options: popoverOptions
|
||||
// }, {
|
||||
// cssClass: popoverCssClass
|
||||
// }, this.config, this.deepLinker);
|
||||
|
||||
// // ev.target is readonly.
|
||||
// // place popover regarding to ion-select instead of .button-inner
|
||||
// Object.defineProperty(ev, 'target', { value: ev.currentTarget });
|
||||
// selectOptions.ev = ev;
|
||||
|
||||
// } else {
|
||||
// // default to use the alert interface
|
||||
// this.interface = 'alert';
|
||||
|
||||
// // user cannot provide inputs from selectOptions
|
||||
// // alert inputs must be created by ionic from ion-options
|
||||
// selectOptions.inputs = this._options.map(input => {
|
||||
// return {
|
||||
// type: (this._multi ? 'checkbox' : 'radio'),
|
||||
// label: input.text,
|
||||
// value: input.value,
|
||||
// checked: input.selected,
|
||||
// disabled: input.disabled,
|
||||
// handler: (selectedOption: any) => {
|
||||
// // Only emit the select event if it is being checked
|
||||
// // For multi selects this won't emit when unchecking
|
||||
// if (selectedOption.checked) {
|
||||
// input.ionSelect.emit(input.value);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// });
|
||||
|
||||
// var selectCssClass = 'select-alert';
|
||||
|
||||
// // create the alert instance from our built up selectOptions
|
||||
// overlay = new Alert(this._app, selectOptions, this.config);
|
||||
|
||||
// if (this._multi) {
|
||||
// // use checkboxes
|
||||
// selectCssClass += ' multiple-select-alert';
|
||||
// } else {
|
||||
// // use radio buttons
|
||||
// selectCssClass += ' single-select-alert';
|
||||
// }
|
||||
|
||||
// // If the user passed a cssClass for the select, add it
|
||||
// selectCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
|
||||
// overlay.setCssClass(selectCssClass);
|
||||
|
||||
// overlay.addButton({
|
||||
// text: this.okText,
|
||||
// handler: (selectedValues) => this.value = selectedValues
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
// overlay.present(selectOptions);
|
||||
|
||||
// this._fireFocus();
|
||||
|
||||
// overlay.onDidDismiss(() => {
|
||||
// this._fireBlur();
|
||||
// this._overlay = undefined;
|
||||
// });
|
||||
|
||||
// this._overlay = overlay;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Close the select interface.
|
||||
// */
|
||||
// close(): Promise<any> {
|
||||
// if (!this._overlay || !this.isFocus()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// return this._overlay.dismiss();
|
||||
// }
|
||||
|
||||
|
||||
// /**
|
||||
// * @hidden
|
||||
// */
|
||||
// get text() {
|
||||
// return (this._multi ? this._texts : this._texts.join());
|
||||
// }
|
||||
|
||||
|
||||
// /**
|
||||
// * @private
|
||||
// */
|
||||
// @ContentChildren(Option)
|
||||
// set options(val: QueryList<Option>) {
|
||||
// this._options = val;
|
||||
// const values = this.getValues();
|
||||
// if (values.length === 0) {
|
||||
// // there are no values set at this point
|
||||
// // so check to see who should be selected
|
||||
// // we use writeValue() because we don't want to update ngModel
|
||||
// this.writeValue(val.filter(o => o.selected).map(o => o.value));
|
||||
// } else {
|
||||
// this._inputUpdated();
|
||||
// }
|
||||
// }
|
||||
|
||||
// _inputShouldChange(val: string[]|string): boolean {
|
||||
// return !deepEqual(this._value, val);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * TODO: REMOVE THIS
|
||||
// * @hidden
|
||||
// */
|
||||
// _inputChangeEvent(): any {
|
||||
// return this.value;
|
||||
// }
|
||||
@Prop({ state: true }) value: string;
|
||||
|
||||
// /**
|
||||
// * @hidden
|
||||
@ -362,4 +107,268 @@ export class Select {
|
||||
// this._text = this._texts.join(', ');
|
||||
// }
|
||||
|
||||
// }
|
||||
/**
|
||||
* @output {EventEmitter} Emitted when the selection is cancelled.
|
||||
*/
|
||||
@Event() ionCancel: EventEmitter;
|
||||
|
||||
|
||||
ionViewWillLoad() {
|
||||
// Get the parent item
|
||||
this.item = this.el.closest('ion-item') as HostElement;
|
||||
|
||||
this.setOptions();
|
||||
}
|
||||
|
||||
|
||||
setOptions() {
|
||||
// Get the options
|
||||
this.options = this.el.querySelectorAll('ion-select-option') as NodeListOf<HostElement>;
|
||||
|
||||
const values = this.getValues();
|
||||
if (values.length === 0) {
|
||||
// there are no values set at this point
|
||||
// so check to see who should be selected
|
||||
// we use writeValue() because we don't want to update ngModel
|
||||
// this.writeValue(val.filter(o => o.selected).map(o => o.value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
getValues(): any[] {
|
||||
const values = Array.isArray(this.value) ? this.value : [this.value];
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the select interface.
|
||||
*/
|
||||
close(): Promise<any> | void {
|
||||
// TODO check !this.overlay || !this.isFocus()
|
||||
if (!this.overlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.overlay.dismiss();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
getText() {
|
||||
return (this.multiple ? this.texts : this.texts.join());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
resetInterface(ev: Event): string {
|
||||
let selectInterface = this.interface;
|
||||
|
||||
if (selectInterface === 'action-sheet' && this.options.length > 6) {
|
||||
console.warn('Interface cannot be "' + selectInterface + '" with more than 6 options. Using the "alert" interface instead.');
|
||||
selectInterface = 'alert';
|
||||
}
|
||||
|
||||
if ((selectInterface === 'action-sheet' || selectInterface === 'popover') && this.multiple) {
|
||||
console.warn('Interface cannot be "' + selectInterface + '" with a multi-value select. Using the "alert" interface instead.');
|
||||
selectInterface = 'alert';
|
||||
}
|
||||
|
||||
if (selectInterface === 'popover' && !ev) {
|
||||
console.warn('Interface cannot be "' + selectInterface + '" without passing an event. Using the "alert" interface instead.');
|
||||
selectInterface = 'alert';
|
||||
}
|
||||
|
||||
return selectInterface;
|
||||
}
|
||||
|
||||
// TODO add Alert to finish this
|
||||
buildAlert(selectOptions: any) {
|
||||
console.debug('Build Select: Alert with', selectOptions, this.options);
|
||||
|
||||
// user cannot provide inputs from selectOptions
|
||||
// alert inputs must be created by ionic from ion-select-options
|
||||
selectOptions.inputs = Array.from(this.options).map((input: any) => {
|
||||
return {
|
||||
type: (this.multiple ? 'checkbox' : 'radio'),
|
||||
label: input.text,
|
||||
value: input.value,
|
||||
checked: input.selected,
|
||||
disabled: input.disabled,
|
||||
handler: (selectedOption: any) => {
|
||||
// Only emit the select event if it is being checked
|
||||
// For multi selects this won't emit when unchecking
|
||||
if (selectedOption.checked) {
|
||||
input.ionSelect.emit(input.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// If multiple is true use checkboxes, else use radio buttons
|
||||
var selectCssClass = 'select-alert ' + this.multiple ? 'multiple-select-alert' : 'single-select-alert';
|
||||
|
||||
// If the user passed a cssClass for the select, add it
|
||||
selectCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
|
||||
|
||||
// create the alert instance from our built up selectOptions
|
||||
// overlay = new Alert(this._app, selectOptions, this.config);
|
||||
|
||||
// overlay.setCssClass(selectCssClass);
|
||||
|
||||
// overlay.addButton({
|
||||
// text: this.okText,
|
||||
// handler: (selectedValues) => this.value = selectedValues
|
||||
// });
|
||||
|
||||
console.debug('Built Select: Alert with', selectOptions, selectCssClass);
|
||||
// return overlay;
|
||||
}
|
||||
|
||||
buildActionSheet(selectOptions: any) {
|
||||
console.debug('Building Select: Action Sheet with', selectOptions, this.options);
|
||||
|
||||
selectOptions.buttons = selectOptions.buttons.concat(Array.from(this.options).map((option: any) => {
|
||||
return {
|
||||
role: (option.selected ? 'selected' : ''),
|
||||
text: option.getText(),
|
||||
handler: () => {
|
||||
this.value = option.value;
|
||||
// TODO remove $instance
|
||||
option.$instance.ionSelect.emit(option.value);
|
||||
}
|
||||
};
|
||||
}));
|
||||
|
||||
var selectCssClass = 'select-action-sheet';
|
||||
|
||||
// If the user passed a cssClass for the select, add it
|
||||
selectCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
|
||||
|
||||
selectOptions.cssClass = selectCssClass;
|
||||
|
||||
console.debug('Built Select: Action Sheet with', selectOptions, selectCssClass);
|
||||
return this.actionSheetCtrl.create(selectOptions);
|
||||
}
|
||||
|
||||
buildPopover(selectOptions: any) {
|
||||
console.debug('Building Select: Popover with', selectOptions, this.options);
|
||||
|
||||
selectOptions = Array.from(this.options).map((option: any) => {
|
||||
return {
|
||||
text: option.getText(),
|
||||
checked: option.selected,
|
||||
disabled: option.disabled,
|
||||
value: option.value,
|
||||
handler: () => {
|
||||
this.value = option.value;
|
||||
option.ionSelect.emit(option.value);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var selectCssClass = 'select-popover';
|
||||
|
||||
// If the user passed a cssClass for the select, add it
|
||||
selectCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
|
||||
|
||||
console.debug('Built Select: Popover with', selectOptions, selectCssClass);
|
||||
|
||||
return this.popoverCtrl.create({
|
||||
component: 'ion-select-popover',
|
||||
componentProps: {
|
||||
options: selectOptions
|
||||
},
|
||||
cssClass: selectCssClass,
|
||||
ev: event
|
||||
});
|
||||
}
|
||||
|
||||
open(ev: UIEvent) {
|
||||
// the user may have assigned some options specifically for the alert
|
||||
const selectOptions = deepCopy(this.selectOptions);
|
||||
|
||||
// make sure their buttons array is removed from the options
|
||||
// and we create a new array for the alert's two buttons
|
||||
selectOptions.buttons = [{
|
||||
text: this.cancelText,
|
||||
role: 'cancel',
|
||||
handler: () => {
|
||||
this.ionCancel.emit(this);
|
||||
}
|
||||
}];
|
||||
|
||||
// if the selectOptions didn't provide a title then use the label's text
|
||||
if (!selectOptions.title && this.item) {
|
||||
selectOptions.title = this.item.getLabelText();
|
||||
}
|
||||
|
||||
// If the user passed in an invalid interface we need to reset it to alert
|
||||
let selectInterface = this.resetInterface(ev);
|
||||
|
||||
let controller: Promise<any>;
|
||||
|
||||
if (selectInterface === 'action-sheet') {
|
||||
controller = this.buildActionSheet(selectOptions);
|
||||
} else if (selectInterface === 'popover') {
|
||||
controller = this.buildPopover(selectOptions);
|
||||
} else {
|
||||
this.buildAlert(selectOptions);
|
||||
}
|
||||
|
||||
controller.then((component: any) => {
|
||||
component.present();
|
||||
|
||||
// component.onDidDismiss(() => {
|
||||
// this.overlay = undefined;
|
||||
// })
|
||||
|
||||
// this.overlay = component;
|
||||
});
|
||||
}
|
||||
|
||||
hostData() {
|
||||
return {
|
||||
class: {
|
||||
'select-disabled': this.disabled
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let addPlaceholderClass = false;
|
||||
|
||||
// If selected text has been passed in, use that first
|
||||
let selectText = this.selectedText || this.text;
|
||||
if (!selectText && this.placeholder) {
|
||||
selectText = this.placeholder;
|
||||
addPlaceholderClass = true;
|
||||
}
|
||||
|
||||
const selectTextClasses: CssClassMap = {
|
||||
'select-text': true,
|
||||
'select-placeholder': addPlaceholderClass
|
||||
};
|
||||
|
||||
return [
|
||||
<div class={ selectTextClasses }>{ selectText }</div>,
|
||||
<div class="select-icon">
|
||||
<div class="select-icon-inner"></div>
|
||||
</div>,
|
||||
<button
|
||||
aria-haspopup="true"
|
||||
id={this.id}
|
||||
aria-labelledby={this.labelId}
|
||||
aria-disabled={this.disabled ? "true" : false}
|
||||
onClick={this.open.bind(this)}
|
||||
class="item-cover">
|
||||
</button>
|
||||
];
|
||||
}
|
||||
}
|
@ -21,61 +21,61 @@
|
||||
<ion-item>
|
||||
<ion-label>Gender</ion-label>
|
||||
<ion-select name="gender" placeholder="Select One">
|
||||
<ion-option value="f">Female</ion-option>
|
||||
<ion-option value="m">Male</ion-option>
|
||||
<ion-select-option value="f">Female</ion-select-option>
|
||||
<ion-select-option value="m">Male</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Hair Color</ion-label>
|
||||
<ion-select name="hairColor" ok-text="Okay" cancel-text="Dismiss">
|
||||
<ion-option value="brown">Brown</ion-option>
|
||||
<ion-option value="blonde">Blonde</ion-option>
|
||||
<ion-option value="black">Black</ion-option>
|
||||
<ion-option value="red">Red</ion-option>
|
||||
<ion-select-option value="brown">Brown</ion-select-option>
|
||||
<ion-select-option value="blonde">Blonde</ion-select-option>
|
||||
<ion-select-option value="black">Black</ion-select-option>
|
||||
<ion-select-option value="red">Red</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Gaming</ion-label>
|
||||
<ion-select name="gaming" ok-text="Okay" cancel-text="Dismiss">
|
||||
<ion-option value="nes">NES</ion-option>
|
||||
<ion-option value="n64">Nintendo64</ion-option>
|
||||
<ion-option value="ps">PlayStation</ion-option>
|
||||
<ion-option value="genesis">Sega Genesis</ion-option>
|
||||
<ion-option value="saturn">Sega Saturn</ion-option>
|
||||
<ion-option value="snes">SNES</ion-option>
|
||||
<ion-select-option value="nes">NES</ion-select-option>
|
||||
<ion-select-option value="n64">Nintendo64</ion-select-option>
|
||||
<ion-select-option value="ps">PlayStation</ion-select-option>
|
||||
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
|
||||
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
|
||||
<ion-select-option value="snes">SNES</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Date</ion-label>
|
||||
<ion-select (ionChange)="monthChange($event)" placeholder="Month">
|
||||
<ion-option value="01">January</ion-option>
|
||||
<ion-option value="02">February</ion-option>
|
||||
<ion-option value="03" selected="true">March</ion-option>
|
||||
<ion-option value="04">April</ion-option>
|
||||
<ion-option value="05">May</ion-option>
|
||||
<ion-option value="06">June</ion-option>
|
||||
<ion-option value="07">July</ion-option>
|
||||
<ion-option value="08">August</ion-option>
|
||||
<ion-option value="09">September</ion-option>
|
||||
<ion-option value="10">October</ion-option>
|
||||
<ion-option value="11">November</ion-option>
|
||||
<ion-option value="12">December</ion-option>
|
||||
<ion-select-option value="01">January</ion-select-option>
|
||||
<ion-select-option value="02">February</ion-select-option>
|
||||
<ion-select-option value="03" selected="true">March</ion-select-option>
|
||||
<ion-select-option value="04">April</ion-select-option>
|
||||
<ion-select-option value="05">May</ion-select-option>
|
||||
<ion-select-option value="06">June</ion-select-option>
|
||||
<ion-select-option value="07">July</ion-select-option>
|
||||
<ion-select-option value="08">August</ion-select-option>
|
||||
<ion-select-option value="09">September</ion-select-option>
|
||||
<ion-select-option value="10">October</ion-select-option>
|
||||
<ion-select-option value="11">November</ion-select-option>
|
||||
<ion-select-option value="12">December</ion-select-option>
|
||||
</ion-select>
|
||||
<ion-select (ionChange)="yearChange($event)" placeholder="Year">
|
||||
<ion-option>1989</ion-option>
|
||||
<ion-option>1990</ion-option>
|
||||
<ion-option>1991</ion-option>
|
||||
<ion-option>1992</ion-option>
|
||||
<ion-option>1993</ion-option>
|
||||
<ion-option selected="true">1994</ion-option>
|
||||
<ion-option>1995</ion-option>
|
||||
<ion-option>1996</ion-option>
|
||||
<ion-option>1997</ion-option>
|
||||
<ion-option>1998</ion-option>
|
||||
<ion-option>1999</ion-option>
|
||||
<ion-select-option>1989</ion-select-option>
|
||||
<ion-select-option>1990</ion-select-option>
|
||||
<ion-select-option>1991</ion-select-option>
|
||||
<ion-select-option>1992</ion-select-option>
|
||||
<ion-select-option>1993</ion-select-option>
|
||||
<ion-select-option selected="true">1994</ion-select-option>
|
||||
<ion-select-option>1995</ion-select-option>
|
||||
<ion-select-option>1996</ion-select-option>
|
||||
<ion-select-option>1997</ion-select-option>
|
||||
<ion-select-option>1998</ion-select-option>
|
||||
<ion-select-option>1999</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
@ -87,51 +87,78 @@
|
||||
<ion-item>
|
||||
<ion-label>Gender</ion-label>
|
||||
<ion-select name="gender" interface="popover">
|
||||
<ion-option value="f">Female</ion-option>
|
||||
<ion-option value="m">Male</ion-option>
|
||||
<ion-select-option value="f">Female</ion-select-option>
|
||||
<ion-select-option value="m">Male</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Gaming</ion-label>
|
||||
<ion-select name="gaming" ok-text="Okay" cancel-text="Dismiss" selected-text="Nintendo 64" interface="popover">
|
||||
<ion-option value="nes">NES</ion-option>
|
||||
<ion-option value="n64">Nintendo64</ion-option>
|
||||
<ion-option value="ps">PlayStation</ion-option>
|
||||
<ion-option value="genesis">Sega Genesis</ion-option>
|
||||
<ion-option value="saturn">Sega Saturn</ion-option>
|
||||
<ion-option value="snes">SNES</ion-option>
|
||||
<ion-select-option value="nes">NES</ion-select-option>
|
||||
<ion-select-option value="n64">Nintendo64</ion-select-option>
|
||||
<ion-select-option value="ps">PlayStation</ion-select-option>
|
||||
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
|
||||
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
|
||||
<ion-select-option value="snes">SNES</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Date</ion-label>
|
||||
<ion-select (ionChange)="monthChange($event)" placeholder="Month" interface="popover">
|
||||
<ion-option value="01">January</ion-option>
|
||||
<ion-option value="02">February</ion-option>
|
||||
<ion-option value="03" selected="true">March</ion-option>
|
||||
<ion-option value="04">April</ion-option>
|
||||
<ion-option value="05">May</ion-option>
|
||||
<ion-option value="06">June</ion-option>
|
||||
<ion-option value="07">July</ion-option>
|
||||
<ion-option value="08">August</ion-option>
|
||||
<ion-option value="09">September</ion-option>
|
||||
<ion-option value="10">October</ion-option>
|
||||
<ion-option value="11">November</ion-option>
|
||||
<ion-option value="12">December</ion-option>
|
||||
<ion-select-option value="01">January</ion-select-option>
|
||||
<ion-select-option value="02">February</ion-select-option>
|
||||
<ion-select-option value="03" selected="true">March</ion-select-option>
|
||||
<ion-select-option value="04">April</ion-select-option>
|
||||
<ion-select-option value="05">May</ion-select-option>
|
||||
<ion-select-option value="06">June</ion-select-option>
|
||||
<ion-select-option value="07">July</ion-select-option>
|
||||
<ion-select-option value="08">August</ion-select-option>
|
||||
<ion-select-option value="09">September</ion-select-option>
|
||||
<ion-select-option value="10">October</ion-select-option>
|
||||
<ion-select-option value="11">November</ion-select-option>
|
||||
<ion-select-option value="12">December</ion-select-option>
|
||||
</ion-select>
|
||||
<ion-select (ionChange)="yearChange($event)" placeholder="Year" interface="popover">
|
||||
<ion-option>1989</ion-option>
|
||||
<ion-option>1990</ion-option>
|
||||
<ion-option>1991</ion-option>
|
||||
<ion-option>1992</ion-option>
|
||||
<ion-option>1993</ion-option>
|
||||
<ion-option selected="true">1994</ion-option>
|
||||
<ion-option>1995</ion-option>
|
||||
<ion-option>1996</ion-option>
|
||||
<ion-option>1997</ion-option>
|
||||
<ion-option>1998</ion-option>
|
||||
<ion-option>1999</ion-option>
|
||||
<ion-select-option>1989</ion-select-option>
|
||||
<ion-select-option>1990</ion-select-option>
|
||||
<ion-select-option>1991</ion-select-option>
|
||||
<ion-select-option>1992</ion-select-option>
|
||||
<ion-select-option>1993</ion-select-option>
|
||||
<ion-select-option selected="true">1994</ion-select-option>
|
||||
<ion-select-option>1995</ion-select-option>
|
||||
<ion-select-option>1996</ion-select-option>
|
||||
<ion-select-option>1997</ion-select-option>
|
||||
<ion-select-option>1998</ion-select-option>
|
||||
<ion-select-option>1999</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
</ion-list>
|
||||
|
||||
|
||||
<ion-list>
|
||||
<ion-list-header>Action Sheet Interface Select</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Mute Notifications</ion-label>
|
||||
<ion-select name="notifications" interface="action-sheet">
|
||||
<ion-select-option value="mute_15">For 15 Minutes</ion-select-option>
|
||||
<ion-select-option value="mute_1">For 1 Hour</ion-select-option>
|
||||
<ion-select-option value="mute_23">For 24 Hours</ion-select-option>
|
||||
<ion-select-option value="mute_inf">Until I turn it back on</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Rating</ion-label>
|
||||
<ion-select name="rating" interface="action-sheet">
|
||||
<ion-select-option value="1">1 Star</ion-select-option>
|
||||
<ion-select-option value="2">2 Stars</ion-select-option>
|
||||
<ion-select-option value="3">3 Stars</ion-select-option>
|
||||
<ion-select-option value="4">4 Stars</ion-select-option>
|
||||
<ion-select-option value="5">5 Stars</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
@ -143,70 +170,44 @@
|
||||
<ion-item>
|
||||
<ion-label>Toppings</ion-label>
|
||||
<ion-select name="toppings" multiple="true" cancel-text="Nah" ok-text="Okay!">
|
||||
<ion-option value="bacon">Bacon</ion-option>
|
||||
<ion-option value="olives">Black Olives</ion-option>
|
||||
<ion-option value="xcheese">Extra Cheese</ion-option>
|
||||
<ion-option value="peppers">Green Peppers</ion-option>
|
||||
<ion-option value="mushrooms">Mushrooms</ion-option>
|
||||
<ion-option value="onions">Onions</ion-option>
|
||||
<ion-option value="pepperoni">Pepperoni</ion-option>
|
||||
<ion-option value="pineapple">Pineapple</ion-option>
|
||||
<ion-option value="sausage">Sausage</ion-option>
|
||||
<ion-option value="Spinach">Spinach</ion-option>
|
||||
<ion-select-option value="bacon">Bacon</ion-select-option>
|
||||
<ion-select-option value="olives">Black Olives</ion-select-option>
|
||||
<ion-select-option value="xcheese">Extra Cheese</ion-select-option>
|
||||
<ion-select-option value="peppers">Green Peppers</ion-select-option>
|
||||
<ion-select-option value="mushrooms">Mushrooms</ion-select-option>
|
||||
<ion-select-option value="onions">Onions</ion-select-option>
|
||||
<ion-select-option value="pepperoni">Pepperoni</ion-select-option>
|
||||
<ion-select-option value="pineapple">Pineapple</ion-select-option>
|
||||
<ion-select-option value="sausage">Sausage</ion-select-option>
|
||||
<ion-select-option value="Spinach">Spinach</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Pets</ion-label>
|
||||
<ion-select name="pets" multiple="true">
|
||||
<ion-option value="bird">Bird</ion-option>
|
||||
<ion-option value="cat">Cat</ion-option>
|
||||
<ion-option value="dog">Dog</ion-option>
|
||||
<ion-option value="honeybadger">Honey Badger</ion-option>
|
||||
<ion-select-option value="bird">Bird</ion-select-option>
|
||||
<ion-select-option value="cat">Cat</ion-select-option>
|
||||
<ion-select-option value="dog">Dog</ion-select-option>
|
||||
<ion-select-option value="honeybadger">Honey Badger</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Skittles</ion-label>
|
||||
<ion-select name="skittles" multiple="true" ok-text="Okay" cancel-text="Dismiss">
|
||||
<ion-option value="red">Red</ion-option>
|
||||
<ion-option value="purple">Purple</ion-option>
|
||||
<ion-option value="yellow">Yellow</ion-option>
|
||||
<ion-option value="orange">Orange</ion-option>
|
||||
<ion-option value="green">Green</ion-option>
|
||||
<ion-select-option value="red">Red</ion-select-option>
|
||||
<ion-select-option value="purple">Purple</ion-select-option>
|
||||
<ion-select-option value="yellow">Yellow</ion-select-option>
|
||||
<ion-select-option value="orange">Orange</ion-select-option>
|
||||
<ion-select-option value="green">Green</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Disabled</ion-label>
|
||||
<ion-select multiple disabled="true">
|
||||
<ion-option checked="true">Selected Text</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
</ion-list>
|
||||
|
||||
<ion-list>
|
||||
<ion-list-header>Action Sheet Interface Select</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Mute Notifications</ion-label>
|
||||
<ion-select name="notifications" interface="action-sheet">
|
||||
<ion-option value="mute_15">For 15 Minutes</ion-option>
|
||||
<ion-option value="mute_1">For 1 Hour</ion-option>
|
||||
<ion-option value="mute_23">For 24 Hours</ion-option>
|
||||
<ion-option value="mute_inf">Until I turn it back on</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Rating</ion-label>
|
||||
<ion-select name="rating" interface="action-sheet">
|
||||
<ion-option value="1">1 Star</ion-option>
|
||||
<ion-option value="2">2 Stars</ion-option>
|
||||
<ion-option value="3">3 Stars</ion-option>
|
||||
<ion-option value="4">4 Stars</ion-option>
|
||||
<ion-option value="5">5 Stars</ion-option>
|
||||
<ion-select-option checked="true">Selected Text</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
|
@ -158,3 +158,8 @@ export function swipeShouldReset(isResetDirection: boolean, isMovingFast: boolea
|
||||
let shouldClose = (!isMovingFast && isOnResetZone) || (isResetDirection && isMovingFast);
|
||||
return shouldClose;
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
export function deepCopy(obj: any) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
@ -10,6 +10,7 @@ A list of the breaking changes introduced in Ionic Angular v4.
|
||||
- [Fixed Content](#fixed-content)
|
||||
- [Icon](#icon)
|
||||
- [Item](#item)
|
||||
- [Option](#option)
|
||||
- [Segment](#segment)
|
||||
- [Toolbar](#toolbar)
|
||||
|
||||
@ -318,6 +319,36 @@ These have been renamed to the following:
|
||||
</ion-item>
|
||||
```
|
||||
|
||||
## Option
|
||||
|
||||
### Markup Changed
|
||||
|
||||
Select's option element should now be written as `<ion-select-option>`. This makes it more obvious that the element should only be used with a Select.
|
||||
|
||||
**Old Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-select>
|
||||
<ion-option>Option 1</ion-option>
|
||||
<ion-option>Option 2</ion-option>
|
||||
<ion-option>Option 3</ion-option>
|
||||
</ion-select>
|
||||
```
|
||||
|
||||
**New Usage Example:**
|
||||
|
||||
```html
|
||||
<ion-select>
|
||||
<ion-select-option>Option 1</ion-select-option>
|
||||
<ion-select-option>Option 2</ion-select-option>
|
||||
<ion-select-option>Option 3</ion-select-option>
|
||||
</ion-select>
|
||||
```
|
||||
|
||||
### Class Changed
|
||||
|
||||
The class has been renamed from `Option` to `SelectOption` to keep it consistent with the element tag name.
|
||||
|
||||
## Segment
|
||||
|
||||
The markup hasn't changed for Segments, but now writing `<ion-segment-button>` will render a native button element inside of it.
|
||||
|
Reference in New Issue
Block a user