import { AfterViewInit, Component, ContentChildren, ElementRef, EventEmitter, forwardRef, Input, HostListener, OnDestroy, Optional, Output, Renderer, QueryList, ViewEncapsulation } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ActionSheet } from '../action-sheet/action-sheet'; import { Alert } from '../alert/alert'; import { App } from '../app/app'; import { Config } from '../../config/config'; import { Form } from '../../util/form'; import { BaseInput } from '../../util/base-input'; import { isCheckedProperty, isTrueProperty, deepCopy, deepEqual } from '../../util/util'; import { Item } from '../item/item'; import { NavController } from '../../navigation/nav-controller'; import { Option } from '../option/option'; export const SELECT_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Select), multi: true }; /** * @name Select * @description * The `ion-select` component is similar to an HTML ` = new EventEmitter(); constructor( private _app: App, form: Form, public config: Config, elementRef: ElementRef, renderer: Renderer, @Optional() item: Item, @Optional() private _nav: NavController ) { super(config, elementRef, renderer, 'select', [], form, item, null); } ngAfterContentInit() { this._inputUpdated(); } @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(); } @HostListener('keyup.space') _keyup() { this.open(); } /** * Open the select interface. */ open() { 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._multi) { console.warn('Interface cannot be "action-sheet" with a multi-value select. Using the "alert" interface.'); this.interface = 'alert'; } let overlay: ActionSheet | Alert; 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 { // 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(); }); } /** * @input {boolean} If true, the element can accept multiple values. */ @Input() get multiple(): any { return this._multi; } set multiple(val: any) { this._multi = isTrueProperty(val); } /** * @hidden */ get text() { return (this._multi ? this._texts : this._texts.join()); } /** * @private */ @ContentChildren(Option) set options(val: QueryList