123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- var __extends = (this && this.__extends) || (function () {
- var extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
- return function (d, b) {
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- };
- })();
- import { Component, ContentChildren, ElementRef, EventEmitter, HostListener, Input, Optional, Output, Renderer, ViewEncapsulation } from '@angular/core';
- import { NG_VALUE_ACCESSOR } from '@angular/forms';
- import { ActionSheet } from '../action-sheet/action-sheet';
- import { Alert } from '../alert/alert';
- import { Popover } from '../popover/popover';
- import { App } from '../app/app';
- import { Config } from '../../config/config';
- import { DeepLinker } from '../../navigation/deep-linker';
- import { Form } from '../../util/form';
- import { BaseInput } from '../../util/base-input';
- import { deepCopy, deepEqual, isCheckedProperty, isTrueProperty } from '../../util/util';
- import { Item } from '../item/item';
- import { Option } from '../option/option';
- import { SelectPopover } from './select-popover-component';
- /**
- * @name Select
- * @description
- * The `ion-select` component is similar to an HTML `<select>` element, however,
- * Ionic's select component makes it easier for users to sort through and select
- * the preferred option or options. When users tap the select component, a
- * dialog will appear with all of the options in a large, easy to select list
- * for users.
- *
- * The select component takes child `ion-option` components. If `ion-option` is not
- * given a `value` attribute then it will use its text as the value.
- *
- * If `ngModel` is bound to `ion-select`, the selected value will be based on the
- * bound value of the model. Otherwise, the `selected` attribute can be used on
- * `ion-option` components.
- *
- * ### Interfaces
- *
- * By default, the `ion-select` uses the {@link ../../alert/AlertController AlertController API}
- * to open up the overlay of options in an alert. The interface can be changed to use the
- * {@link ../../action-sheet/ActionSheetController ActionSheetController API} or
- * {@link ../../popover/PopoverController PopoverController API} by passing `action-sheet` or `popover`,
- * respectively, to the `interface` property. Read on to the other sections for the limitations
- * of the different interfaces.
- *
- * ### Single Value: Radio Buttons
- *
- * The standard `ion-select` component allows the user to select only one
- * option. When selecting only one option the alert interface presents users with
- * a radio button styled list of options. The action sheet interface can only be
- * used with a single value select. If the number of options exceed 6, it will
- * use the `alert` interface even if `action-sheet` is passed. The `ion-select`
- * component's value receives the value of the selected option's value.
- *
- * ```html
- * <ion-item>
- * <ion-label>Gender</ion-label>
- * <ion-select [(ngModel)]="gender">
- * <ion-option value="f">Female</ion-option>
- * <ion-option value="m">Male</ion-option>
- * </ion-select>
- * </ion-item>
- * ```
- *
- * ### Multiple Value: Checkboxes
- *
- * By adding the `multiple="true"` attribute to `ion-select`, users are able
- * to select multiple options. When multiple options can be selected, the alert
- * overlay presents users with a checkbox styled list of options. The
- * `ion-select multiple="true"` component's value receives an array of all the
- * selected option values. In the example below, because each option is not given
- * a `value`, then it'll use its text as the value instead.
- *
- * Note: the `action-sheet` and `popover` interfaces will not work with a multi-value select.
- *
- * ```html
- * <ion-item>
- * <ion-label>Toppings</ion-label>
- * <ion-select [(ngModel)]="toppings" multiple="true">
- * <ion-option>Bacon</ion-option>
- * <ion-option>Black Olives</ion-option>
- * <ion-option>Extra Cheese</ion-option>
- * <ion-option>Mushrooms</ion-option>
- * <ion-option>Pepperoni</ion-option>
- * <ion-option>Sausage</ion-option>
- * </ion-select>
- * </ion-item>
- * ```
- *
- * ### Select Buttons
- * By default, the two buttons read `Cancel` and `OK`. Each button's text
- * can be customized using the `cancelText` and `okText` attributes:
- *
- * ```html
- * <ion-select okText="Okay" cancelText="Dismiss">
- * ...
- * </ion-select>
- * ```
- *
- * The `action-sheet` and `popover` interfaces do not have an `OK` button, clicking
- * on any of the options will automatically close the overlay and select
- * that value.
- *
- * ### Select Options
- *
- * Since `ion-select` uses the `Alert`, `Action Sheet` and `Popover` interfaces, options can be
- * passed to these components through the `selectOptions` property. This can be used
- * to pass a custom title, subtitle, css class, and more. See the
- * {@link ../../alert/AlertController/#create AlertController API docs},
- * {@link ../../action-sheet/ActionSheetController/#create ActionSheetController API docs}, and
- * {@link ../../popover/PopoverController/#create PopoverController API docs}
- * for the properties that each interface accepts.
- *
- * For example, to change the `mode` of the overlay, pass it into `selectOptions`.
- *
- * ```html
- * <ion-select [selectOptions]="selectOptions">
- * ...
- * </ion-select>
- * ```
- *
- * ```ts
- * this.selectOptions = {
- * title: 'Pizza Toppings',
- * subTitle: 'Select your toppings',
- * mode: 'md'
- * };
- * ```
- *
- * ### Object Value References
- *
- * When using objects for select values, it is possible for the identities of these objects to
- * change if they are coming from a server or database, while the selected value's identity
- * remains the same. For example, this can occur when an existing record with the desired object value
- * is loaded into the select, but the newly retrieved select options now have different identities. This will
- * result in the select appearing to have no value at all, even though the original selection in still intact.
- *
- * Using the `compareWith` `Input` is the solution to this problem
- *
- * ```html
- * <ion-item>
- * <ion-label>Employee</ion-label>
- * <ion-select [(ngModel)]="employee" [compareWith]="compareFn">
- * <ion-option *ngFor="let employee of employees" [value]="employee">{{employee.name}}</ion-option>
- * </ion-select>
- * </ion-item>
- * ```
- *
- * ```ts
- * compareFn(e1: Employee, e2: Employee): boolean {
- * return e1 && e2 ? e1.id === e2.id : e1 === e2;
- * }
- * ```
- *
- * @demo /docs/demos/src/select/
- */
- var Select = (function (_super) {
- __extends(Select, _super);
- function Select(_app, form, config, elementRef, renderer, item, deepLinker) {
- var _this = _super.call(this, config, elementRef, renderer, 'select', [], form, item, null) || this;
- _this._app = _app;
- _this.config = config;
- _this.deepLinker = deepLinker;
- _this._multi = false;
- _this._texts = [];
- _this._text = '';
- _this._compareWith = isCheckedProperty;
- /**
- * @input {string} The text to display on the cancel button. Default: `Cancel`.
- */
- _this.cancelText = 'Cancel';
- /**
- * @input {string} The text to display on the ok button. Default: `OK`.
- */
- _this.okText = 'OK';
- /**
- * @input {any} Any additional options that the `alert` or `action-sheet` interface can take.
- * See the [AlertController API docs](../../alert/AlertController/#create) and the
- * [ActionSheetController API docs](../../action-sheet/ActionSheetController/#create) for the
- * create options for each interface.
- */
- _this.selectOptions = {};
- /**
- * @input {string} The interface the select should use: `action-sheet`, `popover` or `alert`. Default: `alert`.
- */
- _this.interface = '';
- /**
- * @input {string} The text to display instead of the selected option's value.
- */
- _this.selectedText = '';
- /**
- * @output {any} Emitted when the selection was cancelled.
- */
- _this.ionCancel = new EventEmitter();
- return _this;
- }
- Object.defineProperty(Select.prototype, "compareWith", {
- /**
- * @input {Function} The function that will be called to compare object values
- */
- set: function (fn) {
- if (typeof fn !== 'function') {
- throw new Error("compareWith must be a function, but received " + JSON.stringify(fn));
- }
- this._compareWith = fn;
- },
- enumerable: true,
- configurable: true
- });
- Select.prototype._click = function (ev) {
- ev.preventDefault();
- ev.stopPropagation();
- this.open(ev);
- };
- Select.prototype._keyup = function () {
- this.open();
- };
- /**
- * @hidden
- */
- Select.prototype.getValues = function () {
- var values = Array.isArray(this._value) ? this._value : [this._value];
- (void 0) /* assert */;
- return values;
- };
- /**
- * Open the select interface.
- */
- Select.prototype.open = function (ev) {
- var _this = this;
- if (this.isFocus() || this._disabled) {
- return;
- }
- (void 0) /* console.debug */;
- // the user may have assigned some options specifically for the alert
- var 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: function () {
- _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();
- }
- var options = this._options.toArray();
- 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';
- }
- var overlay;
- if (this.interface === 'action-sheet') {
- selectOptions.buttons = selectOptions.buttons.concat(options.map(function (input) {
- return {
- role: (input.selected ? 'selected' : ''),
- text: input.text,
- handler: function () {
- _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') {
- var popoverOptions = options.map(function (input) { return ({
- text: input.text,
- checked: input.selected,
- disabled: input.disabled,
- value: input.value,
- handler: function () {
- _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(function (input) {
- return {
- type: (_this._multi ? 'checkbox' : 'radio'),
- label: input.text,
- value: input.value,
- checked: input.selected,
- disabled: input.disabled,
- handler: function (selectedOption) {
- // 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_1 = '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_1 += ' multiple-select-alert';
- }
- else {
- // use radio buttons
- selectCssClass_1 += ' single-select-alert';
- }
- // If the user passed a cssClass for the select, add it
- selectCssClass_1 += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
- overlay.setCssClass(selectCssClass_1);
- overlay.addButton({
- text: this.okText,
- handler: function (selectedValues) { return _this.value = selectedValues; }
- });
- }
- overlay.present(selectOptions);
- this._fireFocus();
- overlay.onDidDismiss(function () {
- _this._fireBlur();
- _this._overlay = undefined;
- });
- this._overlay = overlay;
- };
- /**
- * Close the select interface.
- */
- Select.prototype.close = function () {
- if (!this._overlay || !this.isFocus()) {
- return;
- }
- return this._overlay.dismiss();
- };
- Object.defineProperty(Select.prototype, "multiple", {
- /**
- * @input {boolean} If true, the element can accept multiple values.
- */
- get: function () {
- return this._multi;
- },
- set: function (val) {
- this._multi = isTrueProperty(val);
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(Select.prototype, "text", {
- /**
- * @hidden
- */
- get: function () {
- return (this._multi ? this._texts : this._texts.join());
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(Select.prototype, "options", {
- /**
- * @private
- */
- set: function (val) {
- this._options = val;
- var 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(function (o) { return o.selected; }).map(function (o) { return o.value; }));
- }
- else {
- this._updateText();
- }
- },
- enumerable: true,
- configurable: true
- });
- Select.prototype._inputShouldChange = function (val) {
- return !deepEqual(this._value, val);
- };
- /**
- * TODO: REMOVE THIS
- * @hidden
- */
- Select.prototype._inputChangeEvent = function () {
- return this.value;
- };
- /**
- * @hidden
- */
- Select.prototype._updateText = function () {
- var _this = this;
- this._texts.length = 0;
- if (this._options) {
- this._options.forEach(function (option) {
- // check this option if the option's value is in the values array
- option.selected = _this.getValues().some(function (selectValue) {
- return _this._compareWith(selectValue, option.value);
- });
- if (option.selected) {
- _this._texts.push(option.text);
- }
- });
- }
- this._text = this._texts.join(', ');
- };
- /**
- * @hidden
- */
- Select.prototype._inputUpdated = function () {
- this._updateText();
- _super.prototype._inputUpdated.call(this);
- };
- Select.decorators = [
- { type: Component, args: [{
- selector: 'ion-select',
- template: '<div *ngIf="!_text" class="select-placeholder select-text">{{placeholder}}</div>' +
- '<div *ngIf="_text" class="select-text">{{selectedText || _text}}</div>' +
- '<div class="select-icon">' +
- '<div class="select-icon-inner"></div>' +
- '</div>' +
- '<button aria-haspopup="true" ' +
- 'type="button" ' +
- '[id]="id" ' +
- 'ion-button="item-cover" ' +
- '[attr.aria-labelledby]="_labelId" ' +
- '[attr.aria-disabled]="_disabled" ' +
- 'class="item-cover">' +
- '</button>',
- host: {
- '[class.select-disabled]': '_disabled'
- },
- providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: Select, multi: true }],
- encapsulation: ViewEncapsulation.None,
- },] },
- ];
- /** @nocollapse */
- Select.ctorParameters = function () { return [
- { type: App, },
- { type: Form, },
- { type: Config, },
- { type: ElementRef, },
- { type: Renderer, },
- { type: Item, decorators: [{ type: Optional },] },
- { type: DeepLinker, },
- ]; };
- Select.propDecorators = {
- 'cancelText': [{ type: Input },],
- 'okText': [{ type: Input },],
- 'placeholder': [{ type: Input },],
- 'selectOptions': [{ type: Input },],
- 'interface': [{ type: Input },],
- 'selectedText': [{ type: Input },],
- 'compareWith': [{ type: Input },],
- 'ionCancel': [{ type: Output },],
- '_click': [{ type: HostListener, args: ['click', ['$event'],] },],
- '_keyup': [{ type: HostListener, args: ['keyup.space',] },],
- 'multiple': [{ type: Input },],
- 'options': [{ type: ContentChildren, args: [Option,] },],
- };
- return Select;
- }(BaseInput));
- export { Select };
- //# sourceMappingURL=select.js.map
|