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:
Brandy Carney
2017-08-18 17:11:43 -04:00
parent b6a0b10e76
commit 30708d1224
11 changed files with 568 additions and 421 deletions

View File

@ -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>

View File

@ -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

View File

@ -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();
}

View 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>;
}
}

View File

@ -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>;
}
}

View 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>
);
}
}

View File

@ -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;
}

View File

@ -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>
];
}
}

View File

@ -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>

View File

@ -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));
}

View File

@ -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.