UNPKG

@catull/igniteui-angular

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

1,423 lines 144 kB
var IgxComboComponent_1; import { __decorate, __metadata, __param } from "tslib"; import { ConnectedPositioningStrategy } from './../services/overlay/position/connected-positioning-strategy'; import { CommonModule } from '@angular/common'; import { AfterViewInit, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, HostBinding, HostListener, Input, NgModule, OnInit, OnDestroy, Output, TemplateRef, ViewChild, Optional, Inject, Injector, Type } from '@angular/core'; import { IgxComboItemDirective, IgxComboEmptyDirective, IgxComboHeaderItemDirective, IgxComboHeaderDirective, IgxComboFooterDirective, IgxComboAddItemDirective, IgxComboToggleIconDirective, IgxComboClearIconDirective } from './combo.directives'; import { FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { IgxCheckboxModule } from '../checkbox/checkbox.component'; import { IgxSelectionAPIService } from '../core/selection'; import { cloneArray } from '../core/utils'; import { IgxStringFilteringOperand, IgxBooleanFilteringOperand } from '../data-operations/filtering-condition'; import { FilteringLogic } from '../data-operations/filtering-expression.interface'; import { IgxForOfModule, IgxForOfDirective } from '../directives/for-of/for_of.directive'; import { IgxIconModule } from '../icon/index'; import { IgxRippleModule } from '../directives/ripple/ripple.directive'; import { IgxToggleModule } from '../directives/toggle/toggle.directive'; import { IgxButtonModule } from '../directives/button/button.directive'; import { IgxDropDownModule } from '../drop-down/index'; import { IgxInputGroupModule, IgxInputGroupComponent } from '../input-group/input-group.component'; import { IgxComboItemComponent } from './combo-item.component'; import { IgxComboDropDownComponent } from './combo-dropdown.component'; import { IgxComboFilteringPipe, IgxComboGroupingPipe } from './combo.pipes'; import { AbsoluteScrollStrategy } from '../services'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { DisplayDensityBase, DisplayDensityToken } from '../core/density'; import { IGX_COMBO_COMPONENT } from './combo.common'; import { IgxComboAddItemComponent } from './combo-add-item.component'; import { IgxComboAPIService } from './combo.api'; import { IgxInputState, IgxInputDirective } from '../directives/input/input.directive'; /** * @hidden */ var DataTypes; (function (DataTypes) { DataTypes["EMPTY"] = "empty"; DataTypes["PRIMITIVE"] = "primitive"; DataTypes["COMPLEX"] = "complex"; DataTypes["PRIMARYKEY"] = "valueKey"; })(DataTypes || (DataTypes = {})); /** * @hidden */ const ItemHeights = { 'comfortable': 40, 'cosy': 32, 'compact': 28, }; /** * @hidden * The default number of items that should be in the combo's * drop-down list if no `[itemsMaxHeight]` is specified */ const itemsInContainer = 10; export var IgxComboState; (function (IgxComboState) { /** * Combo with initial state. */ IgxComboState[IgxComboState["INITIAL"] = 0] = "INITIAL"; /** * Combo with valid state. */ IgxComboState[IgxComboState["VALID"] = 1] = "VALID"; /** * Combo with invalid state. */ IgxComboState[IgxComboState["INVALID"] = 2] = "INVALID"; })(IgxComboState || (IgxComboState = {})); /** * When called with sets A & B, returns A - B (as array); * @hidden */ function diffInSets(set1, set2) { const results = []; set1.forEach(entry => { if (!set2.has(entry)) { results.push(entry); } }); return results; } let NEXT_ID = 0; const noop = () => { }; const ɵ0 = noop; let IgxComboComponent = IgxComboComponent_1 = class IgxComboComponent extends DisplayDensityBase { constructor(elementRef, cdr, selection, comboAPI, _displayDensityOptions, _injector) { super(_displayDensityOptions); this.elementRef = elementRef; this.cdr = cdr; this.selection = selection; this.comboAPI = comboAPI; this._displayDensityOptions = _displayDensityOptions; this._injector = _injector; /** * @hidden @internal */ this.customValueFlag = true; /** * @hidden @internal */ this.defaultFallbackGroup = 'Other'; this.stringFilters = IgxStringFilteringOperand; this.booleanFilters = IgxBooleanFilteringOperand; this._groupKey = ''; this._prevInputValue = ''; this._dataType = ''; this.ngControl = null; this.destroy$ = new Subject(); this._data = []; this._filteredData = []; this._itemHeight = null; this._itemsMaxHeight = null; this._remoteSelection = {}; this._onChangeCallback = noop; this._overlaySettings = { scrollStrategy: new AbsoluteScrollStrategy(), positionStrategy: new ConnectedPositioningStrategy(), modal: false, closeOnOutsideClick: true, excludePositionTarget: true }; this._value = ''; this._valid = IgxComboState.INITIAL; /** * Set custom overlay settings that control how the combo's list of items is displayed. * Set: * ```html * <igx-combo [overlaySettings] = "customOverlaySettings"></igx-combo> * ``` * * ```typescript * const customSettings = { positionStrategy: { settings: { target: myTarget } } }; * combo.overlaySettings = customSettings; * ``` * Get any custom overlay settings used by the combo: * ```typescript * const comboOverlaySettings: OverlaySettings = myCombo.overlaySettings; * ``` */ this.overlaySettings = null; /** * @hidden @internal */ this.searchInput = null; /** * The custom template, if any, that should be used when rendering ITEMS in the combo list * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.itemTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboItem> * <div class="custom-item" let-item let-key="valueKey"> * <div class="custom-item__name">{{ item[key] }}</div> * <div class="custom-item__cost">{{ item.cost }}</div> * </div> * </ng-template> * </igx-combo> * ``` */ this.itemTemplate = null; /** * The custom template, if any, that should be used when rendering the HEADER for the combo items list * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.headerTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboHeader> * <div class="combo__header"> * This is a custom header * </div> * </ng-template> * </igx-combo> * ``` */ this.headerTemplate = null; /** * The custom template, if any, that should be used when rendering the FOOTER for the combo items list * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.footerTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboFooter> * <div class="combo__footer"> * This is a custom footer * </div> * </ng-template> * </igx-combo> * ``` */ this.footerTemplate = null; /** * The custom template, if any, that should be used when rendering HEADER ITEMS for groups in the combo list * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.headerItemTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboHeaderItem let-item let-key="groupKey"> * <div class="custom-item--group">Group header for {{ item[key] }}</div> * </ng-template> * </igx-combo> * ``` */ this.headerItemTemplate = null; /** * The custom template, if any, that should be used when rendering the ADD BUTTON in the combo drop down * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.addItemTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboAddItem> * <button class="combo__add-button"> * Click to add item * </button> * </ng-template> * </igx-combo> * ``` */ this.addItemTemplate = null; /** * The custom template, if any, that should be used when rendering the ADD BUTTON in the combo drop down * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.emptyTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboEmpty> * <div class="combo--empty"> * There are no items to display * </div> * </ng-template> * </igx-combo> * ``` */ this.emptyTemplate = null; /** * The custom template, if any, that should be used when rendering the combo TOGGLE(open/close) button * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.toggleIconTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboToggleIcon let-collapsed> * <igx-icon>{{ collapsed ? 'remove_circle' : 'remove_circle_outline'}}</igx-icon> * </ng-template> * </igx-combo> * ``` */ this.toggleIconTemplate = null; /** * The custom template, if any, that should be used when rendering the combo CLEAR button * * ```typescript * // Set in typescript * const myCustomTemplate: TemplateRef<any> = myComponent.customTemplate; * myComponent.combo.clearIconTemplate = myCustomTemplate; * ``` * ```html * <!-- Set in markup --> * <igx-combo #combo> * ... * <ng-template igxComboClearIcon> * <igx-icon>clear</igx-icon> * </ng-template> * </igx-combo> * ``` */ this.clearIconTemplate = null; this.dropdownContainer = null; /** * Emitted when item selection is changing, before the selection completes * * ```html * <igx-combo (onSelectionChange)='handleSelection()'></igx-combo> * ``` */ this.onSelectionChange = new EventEmitter(); /** * Emitted before the dropdown is opened * * ```html * <igx-combo onOpening='handleOpening($event)'></igx-combo> * ``` */ this.onOpening = new EventEmitter(); /** * Emitted after the dropdown is opened * * ```html * <igx-combo (onOpened)='handleOpened()'></igx-combo> * ``` */ this.onOpened = new EventEmitter(); /** * Emitted before the dropdown is closed * * ```html * <igx-combo (onClosing)='handleClosing($event)'></igx-combo> * ``` */ this.onClosing = new EventEmitter(); /** * Emitted after the dropdown is closed * * ```html * <igx-combo (onClosed)='handleClosed()'></igx-combo> * ``` */ this.onClosed = new EventEmitter(); /** * Emitted when an item is being added to the data collection * * ```html * <igx-combo (onAddition)='handleAdditionEvent()'></igx-combo> * ``` */ this.onAddition = new EventEmitter(); /** * Emitted when the value of the search input changes (e.g. typing, pasting, clear, etc.) * * ```html * <igx-combo (onSearchInput)='handleSearchInputEvent()'></igx-combo> * ``` */ this.onSearchInput = new EventEmitter(); /** * Emitted when new chunk of data is loaded from the virtualization * * ```html * <igx-combo (onDataPreLoad)='handleDataPreloadEvent()'></igx-combo> * ``` */ this.onDataPreLoad = new EventEmitter(); /** * Gets/gets combo id. * * ```typescript * // get * let id = this.combo.id; * ``` * * ```html * <!--set--> * <igx-combo [id]='combo1'></igx-combo> * ``` */ this.id = `igx-combo-${NEXT_ID++}`; /** * @hidden @internal */ this.cssClass = 'igx-combo'; // Independent of display density, at the time being /** * @hidden @internal */ this.role = 'combobox'; /** * Controls whether custom values can be added to the collection * * ```typescript * // get * let comboAllowsCustomValues = this.combo.allowCustomValues; * ``` * * ```html * <!--set--> * <igx-combo [allowCustomValues]='true'></igx-combo> * ``` */ this.allowCustomValues = false; /** * @hidden @internal */ this.filteringLogic = FilteringLogic.Or; /** * Defines the placeholder value for the combo dropdown search field * * ```typescript * // get * let myComboSearchPlaceholder = this.combo.searchPlaceholder; * ``` * * ```html * <!--set--> * <igx-combo [searchPlaceholder]='newPlaceHolder'></igx-combo> * ``` */ this.searchPlaceholder = 'Enter a Search Term'; /** * Combo value data source property. * * ```typescript * // get * let myComboValueKey = this.combo.valueKey; * ``` * * ```html * <!--set--> * <igx-combo [valueKey]='myKey'></igx-combo> * ``` */ this.valueKey = null; /** * An @Input property that enabled/disables filtering in the list. The default is `true`. * ```html *<igx-combo [filterable]="false"> * ``` */ this.filterable = true; /** * An @Input property that enabled/disables combo. The default is `false`. * ```html *<igx-combo [disabled]="'true'"> * ``` */ this.disabled = false; /** * An @Input property that sets how the combo will be styled. * The allowed values are `line`, `box`, `border` and `search`. The default is `box`. * ```html *<igx-combo [type]="'line'"> * ``` */ this.type = 'box'; /** * @hidden @internal */ this.searchValue = ''; this.onStatusChanged = () => { if ((this.ngControl.control.touched || this.ngControl.control.dirty) && (this.ngControl.control.validator || this.ngControl.control.asyncValidator)) { this.valid = this.ngControl.valid ? IgxComboState.VALID : IgxComboState.INVALID; } this.manageRequiredAsterisk(); }; this.comboAPI.register(this); } /** * @hidden @internal */ get displaySearchInput() { return this.filterable || this.allowCustomValues; } /** * @hidden @internal */ get ariaExpanded() { return !this.dropdown.collapsed; } /** * @hidden @internal */ get hasPopUp() { return 'listbox'; } /** * @hidden @internal */ get ariaOwns() { return this.dropdown.id; } /** * Configures the drop down list height * * ```typescript * // get * let myComboItemsMaxHeight = this.combo.itemsMaxHeight; * ``` * * ```html * <!--set--> * <igx-combo [itemsMaxHeight]='320'></igx-combo> * ``` */ get itemsMaxHeight() { if (this._itemsMaxHeight === null || this._itemsMaxHeight === undefined) { return this.itemHeight * itemsInContainer; } return this._itemsMaxHeight; } set itemsMaxHeight(val) { this._itemsMaxHeight = val; } /** * Configures the drop down list item height * * ```typescript * // get * let myComboItemHeight = this.combo.itemHeight; * ``` * * ```html * <!--set--> * <igx-combo [itemHeight]='32'></igx-combo> * ``` */ get itemHeight() { if (this._itemHeight === null || this._itemHeight === undefined) { return ItemHeights[this.displayDensity]; } return this._itemHeight; } set itemHeight(val) { this._itemHeight = val; } /** * @hidden @internal */ get inputEmpty() { return !this.value && !this.placeholder; } /** * Combo data source. * * ```html * <!--set--> * <igx-combo [data]='items'></igx-combo> * ``` */ get data() { return this._data; } set data(val) { this._data = (val) ? val : []; } set displayKey(val) { this._displayKey = val; } /** * Combo text data source property. * * ```typescript * // get * let myComboDisplayKey = this.combo.displayKey; * * // set * this.combo.displayKey = 'val'; * * ``` * * ```html * <!--set--> * <igx-combo [displayKey]='myDisplayKey'></igx-combo> * ``` */ get displayKey() { return this._displayKey ? this._displayKey : this.valueKey; } /** * The item property by which items should be grouped inside the items list. Not usable if data is not of type Object[]. * * ```html * <!--set--> * <igx-combo [groupKey]='newGroupKey'></igx-combo> * ``` */ set groupKey(val) { this._groupKey = val; } /** * The item property by which items should be grouped inside the items list. Not usable if data is not of type Object[]. * * ```typescript * // get * let currentGroupKey = this.combo.groupKey; * ``` */ get groupKey() { return this._groupKey; } /** * Gets if control is valid, when used in a form * * ```typescript * // get * let valid = this.combo.valid; * ``` * */ get valid() { return this._valid; } /** * Sets if control is valid, when used in a form * * ```typescript * // set * this.combo.valid = IgxComboState.INVALID; * ``` */ set valid(valid) { this._valid = valid; this.comboInput.valid = IgxInputState[IgxComboState[valid]]; } /** * @hidden @internal */ onArrowDown(event) { event.preventDefault(); event.stopPropagation(); this.open(); } /** * @hidden @internal */ onInputClick(event) { event.stopPropagation(); event.preventDefault(); this.toggle(); } /** * Defines the current state of the virtualized data. It contains `startIndex` and `chunkSize` * * ```typescript * // get * let state = this.combo.virtualizationState; * ``` */ get virtualizationState() { return this.virtDir.state; } /** * Sets the current state of the virtualized data. * * ```typescript * // set * this.combo.virtualizationState(state); * ``` */ set virtualizationState(state) { this.virtDir.state = state; } /** * Gets total count of the virtual data items, when using remote service. * * ```typescript * // get * let count = this.combo.totalItemCount; * ``` */ get totalItemCount() { return this.virtDir.totalItemCount; } /** * Sets total count of the virtual data items, when using remote service. * * ```typescript * // set * this.combo.totalItemCount(remoteService.count); * ``` */ set totalItemCount(count) { this.virtDir.totalItemCount = count; } /** * The text displayed in the combo input * * ```typescript * // get * let comboValue = this.combo.value; * ``` */ get value() { return this._value; } /** * @hidden @internal */ get filteredData() { return this.filterable ? this._filteredData : this.data; } /** * @hidden @internal */ set filteredData(val) { this._filteredData = this.groupKey ? (val || []).filter((e) => e.isHeader !== true) : val; this.checkMatch(); } /** * @hidden @internal */ handleKeyUp(event) { if (event.key === 'ArrowDown' || event.key === 'Down') { this.dropdown.focusedItem = this.dropdown.items[0]; this.dropdownContainer.nativeElement.focus(); } else if (event.key === 'Escape' || event.key === 'Esc') { this.toggle(); } } /** * @hidden @internal */ handleKeyDown(event) { if (event.key === 'ArrowUp' || event.key === 'Up') { event.preventDefault(); event.stopPropagation(); this.close(); } } checkMatch() { const displayKey = this.displayKey; const matchFn = (e) => { const value = displayKey ? e[displayKey] : e; return value.toString().toLowerCase() === this.searchValue.trim().toLowerCase(); }; const itemMatch = this.filteredData.some(matchFn); this.customValueFlag = this.allowCustomValues && !itemMatch; } /** * @hidden @internal */ handleInputChange(event) { if (event !== undefined) { this.onSearchInput.emit(event); } this.checkMatch(); } /** * @hidden @internal */ get dataType() { if (this.displayKey) { return DataTypes.COMPLEX; } return DataTypes.PRIMITIVE; } /** * @hidden @internal */ get isRemote() { return this.totalItemCount > 0 && this.valueKey && this.dataType === DataTypes.COMPLEX; } /** Contains key-value pairs of the selected valueKeys and their resp. displayKeys */ registerRemoteEntries(ids, add = true) { if (add) { const selection = this.getValueDisplayPairs(ids); for (const entry of selection) { this._remoteSelection[entry[this.valueKey]] = entry[this.displayKey]; } } else { for (const entry of ids) { delete this._remoteSelection[entry]; } } } /** For `id: any[]` returns a mapped `{ [combo.valueKey]: any, [combo.displayKey]: any }[]`*/ getValueDisplayPairs(ids) { return this.data.filter(entry => ids.indexOf(entry[this.valueKey]) > -1).map(e => { return { [this.valueKey]: e[this.valueKey], [this.displayKey]: e[this.displayKey] }; }); } /** * Returns if the specified itemID is selected * @hidden * @internal */ isItemSelected(item) { return this.selection.is_item_selected(this.id, item); } /** * Triggers change detection on the combo view */ triggerCheck() { this.cdr.detectChanges(); } /** * @hidden @internal */ isAddButtonVisible() { // This should always return a boolean value. If this.searchValue was '', it returns '' instead of false; return this.searchValue !== '' && this.customValueFlag; } /** * @hidden @internal */ handleSelectAll(evt) { if (evt.checked) { this.selectAllItems(); } else { this.deselectAllItems(); } } /** * @hidden @internal */ addItemToCollection() { if (!this.searchValue) { return; } const newValue = this.searchValue.trim(); const addedItem = this.displayKey ? { [this.valueKey]: newValue, [this.displayKey]: newValue } : newValue; if (this.groupKey) { Object.assign(addedItem, { [this.groupKey]: this.defaultFallbackGroup }); } const oldCollection = this.data; const newCollection = [...this.data]; newCollection.push(addedItem); const args = { oldCollection, addedItem, newCollection }; this.onAddition.emit(args); this.data.push(addedItem); // If you mutate the array, no pipe is invoked and the display isn't updated; // if you replace the array, the pipe executes and the display is updated. this.data = cloneArray(this.data); this.selectItems(this.comboAPI.valueKey !== null ? [addedItem[this.valueKey]] : [addedItem], false); this.customValueFlag = false; this.searchInput.nativeElement.focus(); this.dropdown.focusedItem = null; this.virtDir.scrollTo(0); } /** * @hidden @internal */ focusSearchInput(opening) { if (this.displaySearchInput && this.searchInput) { this.searchInput.nativeElement.focus(); } else { if (opening) { this.dropdownContainer.nativeElement.focus(); } else { this.comboInput.nativeElement.focus(); this.toggle(); } } } manageRequiredAsterisk() { if (this.ngControl && this.ngControl.control.validator) { // Run the validation with empty object to check if required is enabled. const error = this.ngControl.control.validator({}); this.inputGroup.isRequired = error && error.required; } } /** * @hidden @internal */ onBlur() { if (this.collapsed) { if (this.ngControl && !this.ngControl.valid) { this.valid = IgxComboState.INVALID; } else { this.valid = IgxComboState.INITIAL; } } } /** * @hidden @internal */ ngOnInit() { this.ngControl = this._injector.get(NgControl, null); this._overlaySettings.positionStrategy.settings.target = this.elementRef.nativeElement; this.selection.set(this.id, new Set()); } /** * @hidden @internal */ ngAfterViewInit() { this.filteredData = [...this.data]; if (this.ngControl) { this.ngControl.statusChanges.pipe(takeUntil(this.destroy$)).subscribe(this.onStatusChanged); this.manageRequiredAsterisk(); this.cdr.detectChanges(); } this.virtDir.onChunkPreload.pipe(takeUntil(this.destroy$)).subscribe((e) => { this.onDataPreLoad.emit(e); }); } /** * @hidden @internal */ ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); this.comboAPI.clear(); this.selection.clear(this.id); } /** * @hidden @internal */ writeValue(value) { this.selectItems(value, true); this.cdr.markForCheck(); } /** * @hidden @internal */ registerOnChange(fn) { this._onChangeCallback = fn; } /** * @hidden @internal */ registerOnTouched(fn) { } /** * @hidden @internal */ setDisabledState(isDisabled) { this.disabled = isDisabled; } /** * @hidden */ getEditElement() { return this.comboInput.nativeElement; } /** * @hidden @internal */ get template() { this._dataType = this.dataType; if (this.itemTemplate) { return this.itemTemplate; } if (this._dataType === DataTypes.COMPLEX) { return this.complexTemplate; } return this.primitiveTemplate; } /** * @hidden @internal */ get context() { return { $implicit: this }; } /** * @hidden @internal */ handleClearItems(event) { this.deselectAllItems(true, event); event.stopPropagation(); } /** * A method that opens/closes the combo. * *```html *<button (click)="combo.toggle()">Toggle Combo</button> *<igx-combo #combo></igx-combo> *``` */ toggle() { const overlaySettings = Object.assign({}, this._overlaySettings, this.overlaySettings); this.dropdown.toggle(overlaySettings); } /** * A method that opens the combo. * *```html *<button (click)="combo.open()">Open Combo</button> *<igx-combo #combo></igx-combo> *``` */ open() { const overlaySettings = Object.assign({}, this._overlaySettings, this.overlaySettings); this.dropdown.open(overlaySettings); } /** * A method that closes the combo. * *```html *<button (click)="combo.close()">Close Combo</button> *<igx-combo #combo></igx-combo> *``` */ close() { this.dropdown.close(); } /** * Gets drop down state. * * ```typescript * let state = this.combo.collapsed; * ``` */ get collapsed() { return this.dropdown.collapsed; } /** * Get current selection state * @returns Array of selected items * ```typescript * let selectedItems = this.combo.selectedItems(); * ``` */ selectedItems() { const items = Array.from(this.selection.get(this.id)); return items; } /** * Select defined items * @param newItems new items to be selected * @param clearCurrentSelection if true clear previous selected items * ```typescript * this.combo.selectItems(["New York", "New Jersey"]); * ``` */ selectItems(newItems, clearCurrentSelection, event) { if (newItems) { const newSelection = this.selection.add_items(this.id, newItems, clearCurrentSelection); this.setSelection(newSelection, event); } } /** * Deselect defined items * @param items items to deselected * ```typescript * this.combo.deselectItems(["New York", "New Jersey"]); * ``` */ deselectItems(items, event) { if (items) { const newSelection = this.selection.delete_items(this.id, items); this.setSelection(newSelection, event); } } /** * Select all (filtered) items * @param ignoreFilter if set to true, selects all items, otherwise selects only the filtered ones. * ```typescript * this.combo.selectAllItems(); * ``` */ selectAllItems(ignoreFilter, event) { const allVisible = this.selection.get_all_ids(ignoreFilter ? this.data : this.filteredData, this.valueKey); const newSelection = this.selection.add_items(this.id, allVisible); this.setSelection(newSelection, event); } /** * Deselect all (filtered) items * @param ignoreFilter if set to true, deselects all items, otherwise deselects only the filtered ones. * ```typescript * this.combo.deselectAllItems(); * ``` */ deselectAllItems(ignoreFilter, event) { let newSelection = this.selection.get_empty(); if (this.filteredData.length !== this.data.length && !ignoreFilter) { newSelection = this.selection.delete_items(this.id, this.selection.get_all_ids(this.filteredData, this.valueKey)); } this.setSelection(newSelection, event); } /** * Selects/Deselects a single item * @param itemID the itemID of the specific item * @param select If the item should be selected (true) or deselected (false) * * Without specified valueKey; * ```typescript * this.combo.valueKey = null; * const items: { field: string, region: string}[] = data; * this.combo.setSelectedItem(items[0], true); * ``` * With specified valueKey; * ```typescript * this.combo.valueKey = 'field'; * const items: { field: string, region: string}[] = data; * this.combo.setSelectedItem('Connecticut', true); * ``` */ setSelectedItem(itemID, select = true, event) { if (itemID === null || itemID === undefined) { return; } if (select) { this.selectItems([itemID], false, event); } else { this.deselectItems([itemID], event); } } setSelection(newSelection, event) { const removed = diffInSets(this.selection.get(this.id), newSelection); const added = diffInSets(newSelection, this.selection.get(this.id)); const args = { newSelection: Array.from(newSelection), oldSelection: Array.from(this.selection.get(this.id) || []), added, removed, event, cancel: false }; this.onSelectionChange.emit(args); if (!args.cancel) { this.selection.select_items(this.id, args.newSelection, true); let value = ''; if (this.isRemote) { if (args.newSelection.length) { const removedItems = args.oldSelection.filter(e => args.newSelection.indexOf(e) < 0); const addedItems = args.newSelection.filter(e => args.oldSelection.indexOf(e) < 0); this.registerRemoteEntries(addedItems); this.registerRemoteEntries(removedItems, false); value = Object.keys(this._remoteSelection).map(e => this._remoteSelection[e]).join(', '); } else { // If new selection is empty, clear all items this.registerRemoteEntries(args.oldSelection, false); } } else { value = this.displayKey !== null && this.displayKey !== undefined ? this.convertKeysToItems(args.newSelection).map(entry => entry[this.displayKey]).join(', ') : args.newSelection.join(', '); } this._value = value; this._onChangeCallback(args.newSelection); } } /** if there is a valueKey - map the keys to data items, else - just return the keys */ convertKeysToItems(keys) { if (this.comboAPI.valueKey === null) { return keys; } // map keys vs. filter data to retain the order of the selected items return keys.map(key => this.data.find(entry => entry[this.valueKey] === key)).filter(e => e !== undefined); } /** * Event handlers * @hidden * @internal */ handleOpening(event) { this.onOpening.emit(event); if (event.cancel) { return; } } /** * @hidden @internal */ handleOpened() { this.triggerCheck(); this.focusSearchInput(true); this.onOpened.emit(); } /** * @hidden @internal */ handleClosing(event) { this.onClosing.emit(event); if (event.cancel) { return; } this.searchValue = ''; this.comboInput.nativeElement.focus(); } /** * @hidden @internal */ handleClosed() { this.onClosed.emit(); } }; IgxComboComponent.ctorParameters = () => [ { type: ElementRef }, { type: ChangeDetectorRef }, { type: IgxSelectionAPIService }, { type: IgxComboAPIService }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DisplayDensityToken,] }] }, { type: Injector, decorators: [{ type: Optional }] } ]; __decorate([ ViewChild(IgxForOfDirective, { read: IgxForOfDirective, static: true }), __metadata("design:type", IgxForOfDirective) ], IgxComboComponent.prototype, "virtDir", void 0); __decorate([ Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "overlaySettings", void 0); __decorate([ ViewChild('inputGroup', { read: IgxInputGroupComponent, static: true }), __metadata("design:type", IgxInputGroupComponent) ], IgxComboComponent.prototype, "inputGroup", void 0); __decorate([ ViewChild('comboInput', { read: IgxInputDirective, static: true }), __metadata("design:type", IgxInputDirective) ], IgxComboComponent.prototype, "comboInput", void 0); __decorate([ ViewChild(IgxComboDropDownComponent, { read: IgxComboDropDownComponent, static: true }), __metadata("design:type", IgxComboDropDownComponent) ], IgxComboComponent.prototype, "dropdown", void 0); __decorate([ ViewChild('searchInput'), __metadata("design:type", ElementRef) ], IgxComboComponent.prototype, "searchInput", void 0); __decorate([ ContentChild(IgxComboItemDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "itemTemplate", void 0); __decorate([ ContentChild(IgxComboHeaderDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "headerTemplate", void 0); __decorate([ ContentChild(IgxComboFooterDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "footerTemplate", void 0); __decorate([ ContentChild(IgxComboHeaderItemDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "headerItemTemplate", void 0); __decorate([ ContentChild(IgxComboAddItemDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "addItemTemplate", void 0); __decorate([ ContentChild(IgxComboEmptyDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "emptyTemplate", void 0); __decorate([ ContentChild(IgxComboToggleIconDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "toggleIconTemplate", void 0); __decorate([ ContentChild(IgxComboClearIconDirective, { read: TemplateRef }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "clearIconTemplate", void 0); __decorate([ ViewChild('primitive', { read: TemplateRef, static: true }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "primitiveTemplate", void 0); __decorate([ ViewChild('complex', { read: TemplateRef, static: true }), __metadata("design:type", TemplateRef) ], IgxComboComponent.prototype, "complexTemplate", void 0); __decorate([ ViewChild(IgxForOfDirective, { static: true }), __metadata("design:type", IgxForOfDirective) ], IgxComboComponent.prototype, "virtualScrollContainer", void 0); __decorate([ ViewChild('dropdownItemContainer', { static: true }), __metadata("design:type", ElementRef) ], IgxComboComponent.prototype, "dropdownContainer", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onSelectionChange", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onOpening", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onOpened", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onClosing", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onClosed", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onAddition", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onSearchInput", void 0); __decorate([ Output(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "onDataPreLoad", void 0); __decorate([ HostBinding('attr.id'), Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "id", void 0); __decorate([ HostBinding('style.width'), Input(), __metadata("design:type", String) ], IgxComboComponent.prototype, "width", void 0); __decorate([ HostBinding('class.igx-combo'), __metadata("design:type", Object) ], IgxComboComponent.prototype, "cssClass", void 0); __decorate([ HostBinding(`attr.role`), __metadata("design:type", Object) ], IgxComboComponent.prototype, "role", void 0); __decorate([ HostBinding('attr.aria-expanded'), __metadata("design:type", Boolean), __metadata("design:paramtypes", []) ], IgxComboComponent.prototype, "ariaExpanded", null); __decorate([ HostBinding('attr.aria-haspopup'), __metadata("design:type", Object), __metadata("design:paramtypes", []) ], IgxComboComponent.prototype, "hasPopUp", null); __decorate([ HostBinding('attr.aria-owns'), __metadata("design:type", Object), __metadata("design:paramtypes", []) ], IgxComboComponent.prototype, "ariaOwns", null); __decorate([ Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "allowCustomValues", void 0); __decorate([ Input(), __metadata("design:type", Number), __metadata("design:paramtypes", [Number]) ], IgxComboComponent.prototype, "itemsMaxHeight", null); __decorate([ Input(), __metadata("design:type", String) ], IgxComboComponent.prototype, "itemsWidth", void 0); __decorate([ Input(), __metadata("design:type", Number), __metadata("design:paramtypes", [Number]) ], IgxComboComponent.prototype, "itemHeight", null); __decorate([ Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "placeholder", void 0); __decorate([ Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "searchPlaceholder", void 0); __decorate([ Input(), __metadata("design:type", Array), __metadata("design:paramtypes", [Array]) ], IgxComboComponent.prototype, "data", null); __decorate([ Input(), __metadata("design:type", String) ], IgxComboComponent.prototype, "valueKey", void 0); __decorate([ Input(), __metadata("design:type", String), __metadata("design:paramtypes", [String]) ], IgxComboComponent.prototype, "displayKey", null); __decorate([ Input(), __metadata("design:type", String), __metadata("design:paramtypes", [String]) ], IgxComboComponent.prototype, "groupKey", null); __decorate([ Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "filterable", void 0); __decorate([ Input(), HostBinding('attr.aria-labelledby'), __metadata("design:type", String) ], IgxComboComponent.prototype, "ariaLabelledBy", void 0); __decorate([ Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "disabled", void 0); __decorate([ Input(), __metadata("design:type", Object) ], IgxComboComponent.prototype, "type", void 0); __decorate([ HostListener('keydown.ArrowDown', ['$event']), HostListener('keydown.Alt.ArrowDown', ['$event']), __metadata("design:type", Function), __metadata("design:paramtypes", [Event]), __metadata("design:returntype", void 0) ], IgxComboComponent.prototype, "onArrowDown", null); IgxComboComponent = IgxComboComponent_1 = __decorate([ Component({ selector: 'igx-combo', template: "<igx-input-group #inputGroup [displayDensity]=\"displayDensity\" [type]=\"type\" (click)=\"onInputClick($event)\">\n <ng-container ngProjectAs=\"[igxLabel]\">\n <ng-content select=\"[igxLabel]\"></ng-content>\n </ng-container>\n <ng-container ngProjectAs=\"igx-prefix\">\n <ng-content select=\"igx-prefix\"></ng-content>\n </ng-container>\n <ng-container ngProjectAs=\"igx-hint, [igxHint]\">\n <ng-content select=\"igx-hint, [igxHint]\"></ng-content>\n </ng-container>\n <input igxInput #comboInput name=\"comboInput\" type=\"text\" [value]=\"value\" readonly [attr.placeholder]=\"placeholder\"\n [disabled]=\"disabled\" (blur)=\"onBlur()\" />\n <ng-container ngProjectAs=\"igx-suffix\">\n <ng-content select=\"igx-suffix\"></ng-content>\n </ng-container>\n <igx-suffix *ngIf=\"value.length\" aria-label=\"Clear Selection\" class=\"igx-combo__clear-button\" igxRipple\n (click)=\"handleClearItems($event)\">\n <ng-container *ngIf=\"clearIconTemplate\">\n <ng-container *ngTemplateOutlet=\"clearIconTemplate\"></ng-container>\n </ng-container>\n <igx-icon *ngIf=\"!clearIconTemplate\" fontSet=\"material\">\n clear\n </igx-icon>\n </igx-suffix>\n <igx-suffix igxButton=\"icon\" class=\"igx-combo__toggle-button\" igxRipple>\n <ng-container *ngIf=\"toggleIconTemplate\">\n <ng-container *ngTemplateOutlet=\"toggleIconTemplate; context: {$implicit: this.collapsed}\"></ng-container>\n </ng-container>\n <igx-icon *ngIf=\"!toggleIconTemplate\" fontSet=\"material\">\n {{ dropdown.collapsed ? 'arrow_drop_down' : 'arrow_drop_up'}}\n </igx-icon>\n </igx-suffix>\n</igx-input-group>\n<igx-combo-drop-down #igxComboDropDown class=\"igx-combo__drop-down\" [displayDensity]=\"displayDensity\"\n [width]=\"itemsWidth || '100%'\" (onOpening)=\"handleOpening($event)\" (onClosing)=\"handleClosing($event)\"\n (onOpened)=\"handleOpened()\" (onClosed)=\"handleClosed()\">\n <igx-input-group *ngIf=\"displaySearchInput\" [displayDensity]=\"displayDensity\" class=\"igx-combo__search\">\n <input class=\"igx-combo-input\" igxInput #searchInput name=\"searchInput\" autocomplete=\"off\" type=\"text\"\n [(ngModel)]=\"searchValue\" (ngModelChange)=\"handleInputChange($event)\" (keyup)=\"handleKeyUp($event)\"\n (keydown)=\"handleKeyDown($event)\" (focus)=\"dropdown.onBlur($event)\" [attr.placeholder]=\"searchPlaceholder\"\n aria-autocomplete=\"both\" [attr.aria-owns]=\"dropdown.id\" [attr.aria-labelledby]=\"ariaLabelledBy\" />\n </igx-input-group>\n <ng-container *ngTemplateOutlet=\"headerTemplate\">\n </ng-container>\n <div #dropdownItemContainer class=\"igx-combo__content\" [style.overflow]=\"'hidden'\"\n [style.maxHeight.px]=\"itemsMaxHeight\" [igxDropDownItemNavigation]=\"dropdown\" (focus)=\"dropdown.onFocus()\"\n [tabindex]=\"dropdown.collapsed ? -1 : 0\" role=\"listbox\" [attr.id]=\"dropdown.id\">\n <igx-combo-item role=\"option\" [itemHeight]='itemHeight'\n *igxFor=\"let item of data\n | comboFiltering:searchValue:displayKey:filterable\n | comboGrouping:groupKey:valueKey;\n index as rowIndex; containerSize: itemsMaxHeight; scrollOrientation: 'vertical'; itemSize: itemHeight\"\n [value]=\"item\" [isHeader]=\"item.isHeader\" [index]=\"rowIndex\">\n <ng-container *ngIf=\"item.isHeader\">\n <ng-container\n *ngTemplateOutlet=\"headerItemTemplate ? headerItemTemplate : headerItemBase;\n context: {$implicit: item, data: data, valueKey: valueKey, groupKey: groupKey, displayKey: displayKey}\">\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"!item.isHeader\">\n <ng-container #listItem\n *ngTemplateOutlet=\"template; context: {$implicit: item, data: data, valueKey: valueKey, displayKey: displayKey};\">\n </ng-container>\n </ng-container>\n </igx-combo-item>\n </div>\n <div class=\"igx-combo__add\" *ngIf=\"filteredData.length === 0 || isAddButtonVisible()\">\n <div class=\"igx-combo__empty\" *ngIf=\"filteredData.length === 0\">\n <ng-container *ngTemplateOutlet=\"emptyTemplate ? emptyTemplate : empty\">\n </ng-container>\n </div>\n <igx-combo-add-item [itemHeight]='itemHeight' *ngIf=\"isAddButtonVisible()\"\n [tabindex]=\"dropdown.collaps