igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
607 lines (601 loc) • 41.5 kB
JavaScript
import * as i3 from 'igniteui-angular/input-group';
import { IgxInputGroupComponent, IgxInputDirective, IgxSuffixDirective, IgxLabelDirective, IgxPrefixDirective, IgxHintDirective } from 'igniteui-angular/input-group';
import { NgTemplateOutlet } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, EventEmitter, HostListener, ViewChild, Output, Component, NgModule } from '@angular/core';
import { FormGroupDirective, NG_VALUE_ACCESSOR } from '@angular/forms';
import { takeUntil } from 'rxjs/operators';
import { PlatformUtil } from 'igniteui-angular/core';
import { IgxTextSelectionDirective, IgxForOfDirective, IgxButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives';
import { IgxIconComponent } from 'igniteui-angular/icon';
import * as i2 from 'igniteui-angular/combo';
import { IgxComboBaseDirective, IgxComboDropDownComponent, IgxComboItemComponent, IgxComboAddItemComponent, IgxComboFilteringPipe, IgxComboGroupingPipe, IgxComboAPIService, IGX_COMBO_COMPONENT, IgxComboAddItemDirective, IgxComboClearIconDirective, IgxComboEmptyDirective, IgxComboFooterDirective, IgxComboHeaderDirective, IgxComboHeaderItemDirective, IgxComboItemDirective, IgxComboToggleIconDirective } from 'igniteui-angular/combo';
import { IgxDropDownItemNavigationDirective } from 'igniteui-angular/drop-down';
/**
* Represents a drop-down list that provides filtering functionality, allowing users to choose a single option from a predefined list.
*
* @igxModule IgxSimpleComboModule
* @igxTheme igx-combo-theme
* @igxKeywords combobox, single combo selection
* @igxGroup Grids & Lists
*
* @remarks
* It provides the ability to filter items as well as perform single selection on the provided data.
* Additionally, it exposes keyboard navigation and custom styling capabilities.
* @example
* ```html
* <igx-simple-combo [itemsMaxHeight]="250" [data]="locationData"
* [displayKey]="'field'" [valueKey]="'field'"
* placeholder="Location" searchPlaceholder="Search...">
* </igx-simple-combo>
* ```
*/
class IgxSimpleComboComponent extends IgxComboBaseDirective {
get value() {
return this._value[0];
}
/**
* Get current selection state
*
* @returns The selected item, if any
* ```typescript
* let mySelection = this.combo.selection;
* ```
*/
get selection() {
return super.selection[0];
}
/** @hidden @internal */
get filteredData() {
return this._filteredData;
}
/** @hidden @internal */
set filteredData(val) {
this._filteredData = this.groupKey ? (val || []).filter((e) => e.isHeader !== true) : val;
this.checkMatch();
}
/** @hidden @internal */
get searchValue() {
return this._searchValue;
}
set searchValue(val) {
this._searchValue = val;
}
get selectedItem() {
return this.selectionService.get(this.id).values().next().value;
}
get hasSelectedItem() {
return !!this.selectionService.get(this.id).size;
}
constructor() {
super();
this.platformUtil = inject(PlatformUtil);
this.formGroupDirective = inject(FormGroupDirective, { optional: true });
/**
* Emitted when item selection is changing, before the selection completes
*
* ```html
* <igx-simple-combo (selectionChanging)='handleSelection()'></igx-simple-combo>
* ```
*/
this.selectionChanging = new EventEmitter();
/** @hidden @internal */
this.composing = false;
this._updateInput = true;
this._collapsing = false;
this.findAllMatches = (element) => {
const value = this.displayKey ? element[this.displayKey] : element;
if (value === null || value === undefined || value === '') {
// we can accept null, undefined and empty strings as empty display values
return true;
}
const searchValue = this.searchValue || this.comboInput.value;
return !!searchValue && value.toString().toLowerCase().includes(searchValue.toLowerCase());
};
this.comboAPI.register(this);
}
/** @hidden @internal */
onArrowDown(event) {
if (this.collapsed) {
event.preventDefault();
event.stopPropagation();
this.open();
}
else {
if (this.virtDir.igxForOf.length > 0 && !this.hasSelectedItem) {
this.dropdown.navigateNext();
this.dropdownContainer.nativeElement.focus();
}
else if (this.allowCustomValues) {
this.addItem?.element.nativeElement.focus();
}
}
}
/**
* Select a defined item
*
* @param item the item to be selected
* ```typescript
* this.combo.select("New York");
* ```
*/
select(item) {
if (item !== undefined) {
const newSelection = this.selectionService.add_items(this.id, item instanceof Array ? item : [item], true);
this.setSelection(newSelection);
}
}
/**
* Deselect the currently selected item
*
* @param item the items to be deselected
* ```typescript
* this.combo.deselect("New York");
* ```
*/
deselect() {
this.clearSelection();
}
/** @hidden @internal */
writeValue(value) {
const oldSelection = super.selection;
this.selectionService.select_items(this.id, this.isValid(value) ? [value] : [], true);
this.cdr.markForCheck();
this._displayValue = this.createDisplayText(super.selection, oldSelection);
this._value = this.valueKey ? super.selection.map(item => item[this.valueKey]) : super.selection;
this.filterValue = this._displayValue?.toString() || '';
}
/** @hidden @internal */
ngAfterViewInit() {
this.virtDir.contentSizeChange.pipe(takeUntil(this.destroy$)).subscribe(() => {
if (super.selection.length > 0) {
const index = this.virtDir.igxForOf.findIndex(e => {
let current = e ? e[this.valueKey] : undefined;
if (this.valueKey === null || this.valueKey === undefined) {
current = e;
}
return current === super.selection[0];
});
if (!this.isRemote) {
// navigate to item only if we have local data
// as with remote data this will fiddle with igxFor's scroll handler
// and will trigger another chunk load which will break the visualization
this.dropdown.navigateItem(index);
}
}
});
this.dropdown.opening.pipe(takeUntil(this.destroy$)).subscribe((args) => {
if (args.cancel) {
return;
}
this._collapsing = false;
const filtered = this.filteredData.find(this.findAllMatches);
if (filtered === undefined || filtered === null) {
this.filterValue = this.searchValue = this.comboInput.value;
return;
}
});
this.dropdown.opened.pipe(takeUntil(this.destroy$)).subscribe(() => {
if (this.composing) {
this.comboInput.focus();
}
});
this.dropdown.closing.pipe(takeUntil(this.destroy$)).subscribe((args) => {
if (args.cancel) {
return;
}
if (this.getEditElement() && !args.event) {
this._collapsing = true;
}
else {
this.clearOnBlur();
this._onTouchedCallback();
}
this.comboInput.focus();
});
// in reactive form the control is not present initially
// and sets the selection to an invalid value in writeValue method
if (!this.isValid(this.selectedItem)) {
this.selectionService.clear(this.id);
this._displayValue = '';
}
super.ngAfterViewInit();
}
/** @hidden @internal */
ngDoCheck() {
if (this.data?.length && super.selection.length && !this._displayValue) {
this._displayValue = this.createDisplayText(super.selection, []);
this._value = this.valueKey ? super.selection.map(item => item[this.valueKey]) : super.selection;
}
}
/** @hidden @internal */
handleInputChange(event) {
if (this.collapsed && this.comboInput.focused) {
this.open();
}
if (event !== undefined) {
this.filterValue = this.searchValue = typeof event === 'string' ? event : event.target.value;
}
if (!this.comboInput.value.trim() && super.selection.length) {
// handle clearing of input by space
this.clearSelection();
this._onChangeCallback(null);
this.filterValue = '';
}
if (super.selection.length) {
const args = {
newValue: undefined,
oldValue: this.selectedItem,
newSelection: undefined,
oldSelection: this.selection,
displayText: typeof event === 'string' ? event : event?.target?.value,
owner: this,
cancel: false
};
this.selectionChanging.emit(args);
if (!args.cancel) {
this.selectionService.select_items(this.id, [], true);
}
}
// when filtering the focused item should be the first item or the currently selected item
if (!this.dropdown.focusedItem || this.dropdown.focusedItem.id !== this.dropdown.items[0].id) {
this.dropdown.navigateFirst();
}
super.handleInputChange(event);
this.composing = true;
}
/** @hidden @internal */
handleInputClick() {
if (this.collapsed) {
this.open();
this.comboInput.focus();
}
}
/** @hidden @internal */
handleKeyDown(event) {
if (event.key === this.platformUtil.KEYMAP.ENTER) {
const filtered = this.filteredData.find(this.findAllMatches);
if (filtered === null || filtered === undefined) {
return;
}
if (!this.dropdown.collapsed) {
const focusedItem = this.dropdown.focusedItem;
if (focusedItem && !focusedItem.isHeader) {
this.select(focusedItem.itemID);
event.preventDefault();
event.stopPropagation();
this.close();
}
else {
event.preventDefault();
event.stopPropagation();
this.comboInput.focus();
}
}
// manually trigger text selection as it will not be triggered during editing
this.textSelection.trigger();
return;
}
if (event.key === this.platformUtil.KEYMAP.BACKSPACE
|| event.key === this.platformUtil.KEYMAP.DELETE) {
this._updateInput = false;
this.clearSelection(true);
}
if (!this.collapsed && event.key === this.platformUtil.KEYMAP.TAB) {
const filtered = this.filteredData.find(this.findAllMatches);
if (filtered === null || filtered === undefined) {
this.clearOnBlur();
this.close();
return;
}
const focusedItem = this.dropdown.focusedItem;
if (focusedItem && !focusedItem.isHeader) {
this.select(focusedItem.itemID);
this.close();
this.textSelection.trigger();
}
else {
this.clearOnBlur();
this.close();
}
}
this.composing = false;
super.handleKeyDown(event);
}
/** @hidden @internal */
handleKeyUp(event) {
if (event.key === this.platformUtil.KEYMAP.ARROW_DOWN) {
this.dropdown.focusedItem = this.hasSelectedItem && this.filteredData.length > 0
? this.dropdown.items.find(i => i.itemID === this.selectedItem)
: this.dropdown.items[0];
this.dropdownContainer.nativeElement.focus();
}
}
/** @hidden @internal */
handleItemKeyDown(event) {
if (event.key === this.platformUtil.KEYMAP.ARROW_UP && event.altKey) {
this.close();
this.comboInput.focus();
return;
}
if (event.key === this.platformUtil.KEYMAP.ENTER) {
this.comboInput.focus();
}
}
/** @hidden @internal */
handleItemClick() {
this.close();
this.comboInput.focus();
}
/** @hidden @internal */
onBlur() {
// when clicking the toggle button to close the combo and immediately clicking outside of it
// the collapsed state is not modified as the dropdown is still not closed
if (this.collapsed || this._collapsing) {
this.clearOnBlur();
}
super.onBlur();
}
/** @hidden @internal */
getEditElement() {
return this.comboInput.nativeElement;
}
/** @hidden @internal */
clearInput(event) {
const oldSelection = this.selection;
this.clearSelection(true);
if (!this.collapsed) {
this.focusSearchInput(true);
}
event.stopPropagation();
if (this.selection !== oldSelection) {
this.comboInput.value = this.filterValue = this.searchValue = '';
}
this.dropdown.focusedItem = null;
this.composing = false;
this.comboInput.focus();
}
/** @hidden @internal */
handleClear(event) {
if (this.disabled) {
return;
}
this.clearInput(event);
}
/** @hidden @internal */
handleClearKeyDown(event) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.clearInput(event);
}
}
/** @hidden @internal */
handleOpened() {
this.triggerCheck();
if (!this.comboInput.focused) {
this.dropdownContainer.nativeElement.focus();
}
this.opened.emit({ owner: this });
}
/** @hidden @internal */
handleClosing(e) {
const args = { owner: this, event: e.event, cancel: e.cancel };
this.closing.emit(args);
e.cancel = args.cancel;
if (e.cancel) {
return;
}
this.composing = false;
// explicitly update selection so that we don't have to force CD
this.textSelection.selected = true;
}
/** @hidden @internal */
focusSearchInput(opening) {
if (opening) {
this.dropdownContainer.nativeElement.focus();
}
else {
this.comboInput.nativeElement.focus();
}
}
/** @hidden @internal */
onClick(event) {
super.onClick(event);
if (this.comboInput.value.length === 0) {
this.virtDir.scrollTo(0);
}
}
setSelection(newSelection) {
const newValueAsArray = newSelection ? Array.from(newSelection) : [];
const oldValueAsArray = Array.from(this.selectionService.get(this.id) || []);
const newItems = this.convertKeysToItems(newValueAsArray);
const oldItems = this.convertKeysToItems(oldValueAsArray);
const displayText = this.createDisplayText(this.convertKeysToItems(newValueAsArray), oldValueAsArray);
const args = {
newValue: newValueAsArray[0],
oldValue: oldValueAsArray[0],
newSelection: newItems[0],
oldSelection: oldItems[0],
displayText,
owner: this,
cancel: false
};
if (args.newSelection !== args.oldSelection) {
this.selectionChanging.emit(args);
}
// TODO: refactor below code as it sets the selection and the display text
if (!args.cancel) {
let argsSelection = this.isValid(args.newValue)
? args.newValue
: [];
argsSelection = Array.isArray(argsSelection) ? argsSelection : [argsSelection];
this.selectionService.select_items(this.id, argsSelection, true);
this._value = argsSelection;
if (this._updateInput) {
this.comboInput.value = this._displayValue = this.searchValue = displayText !== args.displayText
? args.displayText
: this.createDisplayText(super.selection, [args.oldValue]);
}
this._onChangeCallback(args.newValue);
this._updateInput = true;
}
else if (this.isRemote) {
this.registerRemoteEntries(newValueAsArray, false);
}
else {
args.displayText = this.createDisplayText(oldItems, []);
const oldSelectionArray = args.oldSelection ? [args.oldSelection] : [];
this.comboInput.value = this._displayValue = this.searchValue = this.createDisplayText(oldSelectionArray, []);
if (this.isRemote) {
this.registerRemoteEntries(newValueAsArray, false);
}
}
}
createDisplayText(newSelection, oldSelection) {
if (this.isRemote) {
const selection = this.valueKey ? newSelection.map(item => item[this.valueKey]) : newSelection;
return this.getRemoteSelection(selection, oldSelection);
}
if (this.displayKey !== null
&& this.displayKey !== undefined
&& newSelection.length > 0) {
return newSelection.filter(e => e).map(e => e[this.displayKey])[0]?.toString() || '';
}
return newSelection[0]?.toString() || '';
}
getRemoteSelection(newSelection, oldSelection) {
if (!newSelection.length) {
this.registerRemoteEntries(oldSelection, false);
return '';
}
this.registerRemoteEntries(oldSelection, false);
this.registerRemoteEntries(newSelection);
return Object.keys(this._remoteSelection).map(e => this._remoteSelection[e])[0] || '';
}
/** Contains key-value pairs of the selected valueKeys and their resp. displayKeys */
registerRemoteEntries(ids, add = true) {
const selection = this.getValueDisplayPairs(ids)[0];
if (add && selection) {
this._remoteSelection[selection[this.valueKey]] = selection[this.displayKey].toString();
}
else {
this._remoteSelection = {};
}
}
clearSelection(ignoreFilter) {
let newSelection = this.selectionService.get_empty();
if (this.filteredData.length !== this.data.length && !ignoreFilter) {
newSelection = this.selectionService.delete_items(this.id, this.selectionService.get_all_ids(this.filteredData, this.valueKey));
}
if (this.selectionService.get(this.id).size > 0 || this.comboInput.value.trim()) {
this.setSelection(newSelection);
}
}
clearOnBlur() {
if (this.isRemote) {
const searchValue = this.searchValue || this.comboInput.value;
const remoteValue = Object.keys(this._remoteSelection).map(e => this._remoteSelection[e])[0] || '';
if (searchValue !== remoteValue) {
this.clear();
}
return;
}
const filtered = this.filteredData.find(this.findMatch);
// selecting null in primitive data returns undefined as the search text is '', but the item is null
if (filtered === undefined && this.selectedItem !== null || !super.selection.length) {
this.clear();
}
}
getElementVal(element) {
const elementVal = this.displayKey ? element[this.displayKey] : element;
return String(elementVal);
}
clear() {
this.clearSelection(true);
const oldSelection = this.selection;
if (this.selection !== oldSelection) {
this.comboInput.value = this._displayValue = this.searchValue = '';
}
}
isValid(value) {
if (this.formGroupDirective && value === null) {
return false;
}
if (this.required) {
return value !== null && value !== '' && value !== undefined;
}
return value !== undefined;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxSimpleComboComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: IgxSimpleComboComponent, isStandalone: true, selector: "igx-simple-combo", outputs: { selectionChanging: "selectionChanging" }, host: { listeners: { "keydown.ArrowDown": "onArrowDown($event)", "keydown.Alt.ArrowDown": "onArrowDown($event)" } }, providers: [
IgxComboAPIService,
{ provide: IGX_COMBO_COMPONENT, useExisting: IgxSimpleComboComponent },
{ provide: NG_VALUE_ACCESSOR, useExisting: IgxSimpleComboComponent, multi: true }
], viewQueries: [{ propertyName: "dropdown", first: true, predicate: IgxComboDropDownComponent, descendants: true, static: true }, { propertyName: "addItem", first: true, predicate: IgxComboAddItemComponent, descendants: true }, { propertyName: "textSelection", first: true, predicate: IgxTextSelectionDirective, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<igx-input-group #inputGroup [type]=\"type\">\n\n <ng-container ngProjectAs=\"[igxLabel]\">\n <ng-content select=\"[igxLabel]\"></ng-content>\n </ng-container>\n\n <ng-container ngProjectAs=\"igx-prefix\">\n <ng-content select=\"igx-prefix,[igxPrefix]\"></ng-content>\n </ng-container>\n\n <ng-container ngProjectAs=\"igx-hint, [igxHint]\">\n <ng-content select=\"igx-hint, [igxHint]\"></ng-content>\n </ng-container>\n\n <input #comboInput igxInput [value]=\"displayValue\" role=\"combobox\"\n aria-haspopup=\"listbox\" aria-autocomplete=\"list\" aria-readonly=\"false\"\n [attr.aria-expanded]=\"!this.dropdown.collapsed\" [attr.aria-controls]=\"this.dropdown.listId\"\n [attr.aria-labelledby]=\"this.ariaLabelledBy || this.label?.id || this.placeholder\"\n [attr.placeholder]=\"placeholder\" [disabled]=\"disabled\" [igxTextSelection]=\"!composing\"\n [attr.aria-label]=\"getAriaLabel()\"\n (input)=\"handleInputChange($event)\" (click)=\"handleInputClick()\"\n (keyup)=\"handleKeyUp($event)\" (keydown)=\"handleKeyDown($event)\" (blur)=\"onBlur()\" (paste)=\"handleInputChange($event)\"/>\n\n <ng-container ngProjectAs=\"igx-suffix\">\n <ng-content select=\"igx-suffix,[igxSuffix]\"></ng-content>\n </ng-container>\n\n @if (hasSelectedItem) {\n <igx-suffix [attr.aria-label]=\"resourceStrings.igx_combo_clearItems_placeholder\" class=\"igx-combo__clear-button\"\n (click)=\"handleClear($event)\" (keydown)=\"handleClearKeyDown($event)\" [tabindex]=\"disabled ? -1 : 0\" role=\"button\">\n @if (clearIconTemplate) {\n <ng-container *ngTemplateOutlet=\"clearIconTemplate\"></ng-container>\n }\n @if (!clearIconTemplate) {\n <igx-icon family=\"default\" name=\"input_clear\"></igx-icon>\n }\n </igx-suffix>\n }\n\n @if (showSearchCaseIcon) {\n <igx-suffix>\n <igx-icon family=\"default\" name=\"case_sensitive\" [active]=\"filteringOptions.caseSensitive\"\n (click)=\"toggleCaseSensitive()\">\n </igx-icon>\n </igx-suffix>\n }\n\n <igx-suffix class=\"igx-combo__toggle-button\" (click)=\"onClick($event)\" (keydown)=\"handleToggleKeyDown($event)\"\n [tabindex]=\"disabled ? -1 : 0\" role=\"button\">\n @if (toggleIconTemplate) {\n <ng-container *ngTemplateOutlet=\"toggleIconTemplate; context: {$implicit: collapsed}\"></ng-container>\n }\n @if (!toggleIconTemplate) {\n <igx-icon family=\"default\" [name]=\"toggleIcon\"></igx-icon>\n }\n </igx-suffix>\n\n</igx-input-group>\n\n<igx-combo-drop-down #igxComboDropDown class=\"igx-combo__drop-down\"\n [labelledBy]=\"this.ariaLabelledBy || this.label?.id || this.placeholder || ''\"\n [width]=\"itemsWidth || '100%'\" (opening)=\"handleOpening($event)\" (closing)=\"handleClosing($event)\"\n (opened)=\"handleOpened()\" (closed)=\"handleClosed()\" [singleMode]=\"true\">\n <ng-container *ngTemplateOutlet=\"headerTemplate\">\n </ng-container>\n <div #dropdownItemContainer class=\"igx-combo__content\" [style.overflow]=\"'hidden'\"\n [style.maxHeight.rem]=\"itemsMaxHeightInRem\" [igxDropDownItemNavigation]=\"dropdown\"\n [tabindex]=\"dropdown.collapsed ? -1 : 0\" [attr.id]=\"dropdown.id\"\n [attr.aria-activedescendant]=\"this.activeDescendant\"\n (focus)=\"dropdown.onFocus()\" (keydown)=\"handleItemKeyDown($event)\">\n <igx-combo-item [role]=\"item?.isHeader? 'group' : 'option'\" [singleMode]=\"true\"\n [itemHeight]=\"itemHeight\" (click)=\"handleItemClick()\" *igxFor=\"let item of data\n | comboFiltering:filterValue:displayKey:filteringOptions:filterFunction:disableFiltering\n | comboGrouping:groupKey:valueKey:groupSortingDirection:compareCollator;\n index as rowIndex; initialChunkSize: 10; containerSize: itemsMaxHeight || containerSize; itemSize: itemHeight || itemSize; scrollOrientation: 'vertical';\"\n [value]=\"item\" [isHeader]=\"item?.isHeader\" [index]=\"rowIndex\">\n @if (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 }\n <!-- if item is 'null' it should be displayed and !!(item?.isHeader) would resolve it to 'false' and not display it -->\n @if (!item?.isHeader) {\n <ng-container #listItem\n *ngTemplateOutlet=\"template; context: {$implicit: item, data: data, valueKey: valueKey, displayKey: displayKey};\">\n </ng-container>\n }\n </igx-combo-item>\n </div>\n\n @if (filteredData.length === 0 || isAddButtonVisible()) {\n <div class=\"igx-combo__add\">\n @if (filteredData.length === 0) {\n <div class=\"igx-combo__empty\">\n <ng-container *ngTemplateOutlet=\"emptyTemplate ? emptyTemplate : empty\">\n </ng-container>\n </div>\n }\n @if (isAddButtonVisible()) {\n <igx-combo-add-item #addItem [itemHeight]=\"itemHeight\"\n [tabindex]=\"dropdown.collapsed ? -1 : customValueFlag ? 1 : -1\" class=\"igx-combo__add-item\" role=\"button\"\n [attr.aria-label]=\"resourceStrings.igx_combo_addCustomValues_placeholder\" [index]=\"virtualScrollContainer.igxForOf.length\">\n <ng-container *ngTemplateOutlet=\"addItemTemplate ? addItemTemplate : addItemDefault\">\n </ng-container>\n </igx-combo-add-item>\n }\n </div>\n }\n <ng-container *ngTemplateOutlet=\"footerTemplate\">\n </ng-container>\n</igx-combo-drop-down>\n\n<ng-template #complex let-display let-data=\"data\" let-key=\"displayKey\">\n {{display[key]}}\n</ng-template>\n<ng-template #primitive let-display>\n {{display}}\n</ng-template>\n<ng-template #empty>\n <span>{{resourceStrings.igx_combo_empty_message}}</span>\n</ng-template>\n<ng-template #addItemDefault let-control>\n <button type=\"button\" igxButton=\"flat\" igxRipple>{{ resourceStrings.igx_combo_addCustomValues_placeholder }}</button>\n</ng-template>\n<ng-template #headerItemBase let-item let-key=\"valueKey\" let-groupKey=\"groupKey\">\n {{ item[key] }}\n</ng-template>\n", dependencies: [{ kind: "component", type: IgxInputGroupComponent, selector: "igx-input-group", inputs: ["resourceStrings", "suppressInputAutofocus", "type", "theme"] }, { kind: "directive", type: IgxInputDirective, selector: "[igxInput]", inputs: ["value", "disabled", "required"], exportAs: ["igxInput"] }, { kind: "directive", type: IgxTextSelectionDirective, selector: "[igxTextSelection]", inputs: ["igxTextSelection"], exportAs: ["igxTextSelection"] }, { kind: "directive", type: IgxSuffixDirective, selector: "igx-suffix,[igxSuffix],[igxEnd]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IgxIconComponent, selector: "igx-icon", inputs: ["ariaHidden", "family", "name", "active"] }, { kind: "component", type: IgxComboDropDownComponent, selector: "igx-combo-drop-down", inputs: ["singleMode"] }, { kind: "directive", type: IgxDropDownItemNavigationDirective, selector: "[igxDropDownItemNavigation]", inputs: ["igxDropDownItemNavigation"] }, { kind: "directive", type: IgxForOfDirective, selector: "[igxFor][igxForOf]", inputs: ["igxForOf", "igxForSizePropName", "igxForScrollOrientation", "igxForScrollContainer", "igxForContainerSize", "igxForInitialChunkSize", "igxForItemSize", "igxForTotalItemCount", "igxForTrackBy"], outputs: ["chunkLoad", "scrollbarVisibilityChanged", "contentSizeChange", "dataChanged", "beforeViewDestroyed", "chunkPreload"] }, { kind: "component", type: IgxComboItemComponent, selector: "igx-combo-item", inputs: ["itemHeight", "ariaLabel", "singleMode"] }, { kind: "component", type: IgxComboAddItemComponent, selector: "igx-combo-add-item" }, { kind: "directive", type: IgxButtonDirective, selector: "[igxButton]", inputs: ["selected", "igxButton", "igxLabel"], outputs: ["buttonSelected"] }, { kind: "directive", type: IgxRippleDirective, selector: "[igxRipple]", inputs: ["igxRippleTarget", "igxRipple", "igxRippleDuration", "igxRippleCentered", "igxRippleDisabled"] }, { kind: "pipe", type: IgxComboFilteringPipe, name: "comboFiltering" }, { kind: "pipe", type: IgxComboGroupingPipe, name: "comboGrouping" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxSimpleComboComponent, decorators: [{
type: Component,
args: [{ selector: 'igx-simple-combo', providers: [
IgxComboAPIService,
{ provide: IGX_COMBO_COMPONENT, useExisting: IgxSimpleComboComponent },
{ provide: NG_VALUE_ACCESSOR, useExisting: IgxSimpleComboComponent, multi: true }
], imports: [IgxInputGroupComponent, IgxInputDirective, IgxTextSelectionDirective, IgxSuffixDirective, NgTemplateOutlet, IgxIconComponent, IgxComboDropDownComponent, IgxDropDownItemNavigationDirective, IgxForOfDirective, IgxComboItemComponent, IgxComboAddItemComponent, IgxButtonDirective, IgxRippleDirective, IgxComboFilteringPipe, IgxComboGroupingPipe], template: "<igx-input-group #inputGroup [type]=\"type\">\n\n <ng-container ngProjectAs=\"[igxLabel]\">\n <ng-content select=\"[igxLabel]\"></ng-content>\n </ng-container>\n\n <ng-container ngProjectAs=\"igx-prefix\">\n <ng-content select=\"igx-prefix,[igxPrefix]\"></ng-content>\n </ng-container>\n\n <ng-container ngProjectAs=\"igx-hint, [igxHint]\">\n <ng-content select=\"igx-hint, [igxHint]\"></ng-content>\n </ng-container>\n\n <input #comboInput igxInput [value]=\"displayValue\" role=\"combobox\"\n aria-haspopup=\"listbox\" aria-autocomplete=\"list\" aria-readonly=\"false\"\n [attr.aria-expanded]=\"!this.dropdown.collapsed\" [attr.aria-controls]=\"this.dropdown.listId\"\n [attr.aria-labelledby]=\"this.ariaLabelledBy || this.label?.id || this.placeholder\"\n [attr.placeholder]=\"placeholder\" [disabled]=\"disabled\" [igxTextSelection]=\"!composing\"\n [attr.aria-label]=\"getAriaLabel()\"\n (input)=\"handleInputChange($event)\" (click)=\"handleInputClick()\"\n (keyup)=\"handleKeyUp($event)\" (keydown)=\"handleKeyDown($event)\" (blur)=\"onBlur()\" (paste)=\"handleInputChange($event)\"/>\n\n <ng-container ngProjectAs=\"igx-suffix\">\n <ng-content select=\"igx-suffix,[igxSuffix]\"></ng-content>\n </ng-container>\n\n @if (hasSelectedItem) {\n <igx-suffix [attr.aria-label]=\"resourceStrings.igx_combo_clearItems_placeholder\" class=\"igx-combo__clear-button\"\n (click)=\"handleClear($event)\" (keydown)=\"handleClearKeyDown($event)\" [tabindex]=\"disabled ? -1 : 0\" role=\"button\">\n @if (clearIconTemplate) {\n <ng-container *ngTemplateOutlet=\"clearIconTemplate\"></ng-container>\n }\n @if (!clearIconTemplate) {\n <igx-icon family=\"default\" name=\"input_clear\"></igx-icon>\n }\n </igx-suffix>\n }\n\n @if (showSearchCaseIcon) {\n <igx-suffix>\n <igx-icon family=\"default\" name=\"case_sensitive\" [active]=\"filteringOptions.caseSensitive\"\n (click)=\"toggleCaseSensitive()\">\n </igx-icon>\n </igx-suffix>\n }\n\n <igx-suffix class=\"igx-combo__toggle-button\" (click)=\"onClick($event)\" (keydown)=\"handleToggleKeyDown($event)\"\n [tabindex]=\"disabled ? -1 : 0\" role=\"button\">\n @if (toggleIconTemplate) {\n <ng-container *ngTemplateOutlet=\"toggleIconTemplate; context: {$implicit: collapsed}\"></ng-container>\n }\n @if (!toggleIconTemplate) {\n <igx-icon family=\"default\" [name]=\"toggleIcon\"></igx-icon>\n }\n </igx-suffix>\n\n</igx-input-group>\n\n<igx-combo-drop-down #igxComboDropDown class=\"igx-combo__drop-down\"\n [labelledBy]=\"this.ariaLabelledBy || this.label?.id || this.placeholder || ''\"\n [width]=\"itemsWidth || '100%'\" (opening)=\"handleOpening($event)\" (closing)=\"handleClosing($event)\"\n (opened)=\"handleOpened()\" (closed)=\"handleClosed()\" [singleMode]=\"true\">\n <ng-container *ngTemplateOutlet=\"headerTemplate\">\n </ng-container>\n <div #dropdownItemContainer class=\"igx-combo__content\" [style.overflow]=\"'hidden'\"\n [style.maxHeight.rem]=\"itemsMaxHeightInRem\" [igxDropDownItemNavigation]=\"dropdown\"\n [tabindex]=\"dropdown.collapsed ? -1 : 0\" [attr.id]=\"dropdown.id\"\n [attr.aria-activedescendant]=\"this.activeDescendant\"\n (focus)=\"dropdown.onFocus()\" (keydown)=\"handleItemKeyDown($event)\">\n <igx-combo-item [role]=\"item?.isHeader? 'group' : 'option'\" [singleMode]=\"true\"\n [itemHeight]=\"itemHeight\" (click)=\"handleItemClick()\" *igxFor=\"let item of data\n | comboFiltering:filterValue:displayKey:filteringOptions:filterFunction:disableFiltering\n | comboGrouping:groupKey:valueKey:groupSortingDirection:compareCollator;\n index as rowIndex; initialChunkSize: 10; containerSize: itemsMaxHeight || containerSize; itemSize: itemHeight || itemSize; scrollOrientation: 'vertical';\"\n [value]=\"item\" [isHeader]=\"item?.isHeader\" [index]=\"rowIndex\">\n @if (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 }\n <!-- if item is 'null' it should be displayed and !!(item?.isHeader) would resolve it to 'false' and not display it -->\n @if (!item?.isHeader) {\n <ng-container #listItem\n *ngTemplateOutlet=\"template; context: {$implicit: item, data: data, valueKey: valueKey, displayKey: displayKey};\">\n </ng-container>\n }\n </igx-combo-item>\n </div>\n\n @if (filteredData.length === 0 || isAddButtonVisible()) {\n <div class=\"igx-combo__add\">\n @if (filteredData.length === 0) {\n <div class=\"igx-combo__empty\">\n <ng-container *ngTemplateOutlet=\"emptyTemplate ? emptyTemplate : empty\">\n </ng-container>\n </div>\n }\n @if (isAddButtonVisible()) {\n <igx-combo-add-item #addItem [itemHeight]=\"itemHeight\"\n [tabindex]=\"dropdown.collapsed ? -1 : customValueFlag ? 1 : -1\" class=\"igx-combo__add-item\" role=\"button\"\n [attr.aria-label]=\"resourceStrings.igx_combo_addCustomValues_placeholder\" [index]=\"virtualScrollContainer.igxForOf.length\">\n <ng-container *ngTemplateOutlet=\"addItemTemplate ? addItemTemplate : addItemDefault\">\n </ng-container>\n </igx-combo-add-item>\n }\n </div>\n }\n <ng-container *ngTemplateOutlet=\"footerTemplate\">\n </ng-container>\n</igx-combo-drop-down>\n\n<ng-template #complex let-display let-data=\"data\" let-key=\"displayKey\">\n {{display[key]}}\n</ng-template>\n<ng-template #primitive let-display>\n {{display}}\n</ng-template>\n<ng-template #empty>\n <span>{{resourceStrings.igx_combo_empty_message}}</span>\n</ng-template>\n<ng-template #addItemDefault let-control>\n <button type=\"button\" igxButton=\"flat\" igxRipple>{{ resourceStrings.igx_combo_addCustomValues_placeholder }}</button>\n</ng-template>\n<ng-template #headerItemBase let-item let-key=\"valueKey\" let-groupKey=\"groupKey\">\n {{ item[key] }}\n</ng-template>\n" }]
}], ctorParameters: () => [], propDecorators: { dropdown: [{
type: ViewChild,
args: [IgxComboDropDownComponent, { static: true }]
}], addItem: [{
type: ViewChild,
args: [IgxComboAddItemComponent]
}], selectionChanging: [{
type: Output
}], textSelection: [{
type: ViewChild,
args: [IgxTextSelectionDirective, { static: true }]
}], onArrowDown: [{
type: HostListener,
args: ['keydown.ArrowDown', ['$event']]
}, {
type: HostListener,
args: ['keydown.Alt.ArrowDown', ['$event']]
}] } });
/* NOTE: Simple combo directives collection for ease-of-use import in standalone components scenario */
const IGX_SIMPLE_COMBO_DIRECTIVES = [
IgxSimpleComboComponent,
IgxComboAddItemDirective,
IgxComboClearIconDirective,
IgxComboEmptyDirective,
IgxComboFooterDirective,
IgxComboHeaderDirective,
IgxComboHeaderItemDirective,
IgxComboItemDirective,
IgxComboToggleIconDirective,
IgxLabelDirective,
IgxPrefixDirective,
IgxSuffixDirective,
IgxHintDirective
];
/**
* @hidden
* IMPORTANT: The following is NgModule exported for backwards-compatibility before standalone components
*/
class IgxSimpleComboModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxSimpleComboModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.2", ngImport: i0, type: IgxSimpleComboModule, imports: [IgxSimpleComboComponent, i2.IgxComboAddItemDirective, i2.IgxComboClearIconDirective, i2.IgxComboEmptyDirective, i2.IgxComboFooterDirective, i2.IgxComboHeaderDirective, i2.IgxComboHeaderItemDirective, i2.IgxComboItemDirective, i2.IgxComboToggleIconDirective, i3.IgxLabelDirective, i3.IgxPrefixDirective, i3.IgxSuffixDirective, i3.IgxHintDirective], exports: [IgxSimpleComboComponent, i2.IgxComboAddItemDirective, i2.IgxComboClearIconDirective, i2.IgxComboEmptyDirective, i2.IgxComboFooterDirective, i2.IgxComboHeaderDirective, i2.IgxComboHeaderItemDirective, i2.IgxComboItemDirective, i2.IgxComboToggleIconDirective, i3.IgxLabelDirective, i3.IgxPrefixDirective, i3.IgxSuffixDirective, i3.IgxHintDirective] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxSimpleComboModule, imports: [IgxSimpleComboComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxSimpleComboModule, decorators: [{
type: NgModule,
args: [{
imports: [
...IGX_SIMPLE_COMBO_DIRECTIVES
],
exports: [
...IGX_SIMPLE_COMBO_DIRECTIVES
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { IGX_SIMPLE_COMBO_DIRECTIVES, IgxSimpleComboComponent, IgxSimpleComboModule };
//# sourceMappingURL=igniteui-angular-simple-combo.mjs.map