@progress/kendo-angular-dropdowns
Version:
A wide variety of native Angular dropdown components including AutoComplete, ComboBox, DropDownList, DropDownTree, MultiColumnComboBox, MultiSelect, and MultiSelectTree
1,310 lines (1,300 loc) • 758 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import * as i0 from '@angular/core';
import { EventEmitter, Component, Input, HostBinding, Output, Directive, Injectable, HostListener, ViewChildren, ViewChild, forwardRef, isDevMode, ViewContainerRef, ContentChild, ContentChildren, ChangeDetectionStrategy, NgModule } from '@angular/core';
import * as i10 from '@progress/kendo-angular-common';
import { isDocumentAvailable, isObjectPresent, removeHTMLAttributes, parseAttributes, isSafari, Keys, setHTMLAttributes, EventsOutsideAngularDirective, isChanged, TemplateContextDirective, ResizeSensorComponent, closest as closest$1, isControlRequired, hasObservers, KendoInput, SuffixTemplateDirective, PrefixTemplateDirective, SeparatorComponent, MultiTabStop, anyChanged, guid as guid$1, ToggleButtonTabStopDirective, ResizeBatchService, KENDO_ADORNMENTS, KENDO_TOGGLEBUTTONTABSTOP } from '@progress/kendo-angular-common';
export { PrefixTemplateDirective, SeparatorComponent, SuffixTemplateDirective, ToggleButtonTabStopDirective } from '@progress/kendo-angular-common';
import * as i7 from '@progress/kendo-angular-utils';
import { AdaptiveService } from '@progress/kendo-angular-utils';
import * as i8 from '@angular/forms';
import { NgControl, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormsModule } from '@angular/forms';
import { validatePackage } from '@progress/kendo-licensing';
import { getter as getter$1, touchEnabled, pointers } from '@progress/kendo-common';
import * as i1 from '@progress/kendo-angular-l10n';
import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
import { Subscription, merge, fromEvent, Subject, of, interval } from 'rxjs';
import * as i2 from '@progress/kendo-angular-popup';
import { PopupService } from '@progress/kendo-angular-popup';
import { map, switchMap, take, auditTime, tap, filter, partition, throttleTime, catchError, skipWhile, concatMap, takeUntil, debounceTime } from 'rxjs/operators';
import { NgIf, NgStyle, NgFor, NgClass, NgTemplateOutlet } from '@angular/common';
import { xIcon, caretAltDownIcon, searchIcon, xCircleIcon, plusIcon } from '@progress/kendo-svg-icons';
import { IconComponent, IconWrapperComponent, IconsService } from '@progress/kendo-angular-icons';
import { ActionSheetComponent, ActionSheetTemplateDirective } from '@progress/kendo-angular-navigation';
import { TextBoxComponent, TextBoxPrefixTemplateDirective } from '@progress/kendo-angular-inputs';
import { ButtonComponent } from '@progress/kendo-angular-buttons';
import * as i1$1 from '@progress/kendo-angular-treeview';
import { DataBoundComponent, ExpandableComponent, TreeViewComponent, SelectDirective, FlatDataBindingDirective, HierarchyBindingDirective, ExpandDirective } from '@progress/kendo-angular-treeview';
import { DialogContainerService, DialogService, WindowService, WindowContainerService } from '@progress/kendo-angular-dialog';
/**
* @hidden
*/
const packageMetadata = {
name: '@progress/kendo-angular-dropdowns',
productName: 'Kendo UI for Angular',
productCode: 'KENDOUIANGULAR',
productCodes: ['KENDOUIANGULAR'],
publishDate: 1745303969,
version: '18.5.2',
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
};
/* eslint-disable no-bitwise */
/**
* @hidden
*/
const isPresent = (value) => value !== null && value !== undefined;
/**
* @hidden
*/
const isNumber = (value) => !isNaN(value);
/**
* @hidden
*/
const guid = () => {
let id = "";
let i;
let random;
for (i = 0; i < 32; i++) {
random = Math.random() * 16 | 0;
if (i === 8 || i === 12 || i === 16 || i === 20) {
id += "-";
}
id += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16);
}
return id;
};
/**
* @hidden
*/
const combineStr = (begin, end) => {
return begin.concat(end.substr(end.toLowerCase().indexOf(begin.toLowerCase()) + begin.length));
};
/**
* @hidden
*/
const isWindowAvailable = () => typeof window !== 'undefined';
/**
* @hidden
*/
const isArray = (value) => Array.isArray(value);
/**
* @hidden
*/
const isObject = (value) => isPresent(value) && typeof value === 'object';
/**
* @hidden
*/
const isEmptyString = (value) => typeof value === 'string' && value.length === 0;
/**
* @hidden
*/
const resolveValuesInArray = (values, data = [], valueField) => values
.map(value => {
return data.find(item => getter(item, valueField) === value);
})
.filter(value => value !== undefined);
/**
* @hidden
*/
const validateComplexValues = (values, valueField) => isArray(values) && values.filter(item => {
return isObject(item) && getter(item, valueField) !== undefined;
});
/**
* @hidden
*/
const resolveAllValues = (value, data, valueField) => {
const customValues = validateComplexValues(value, valueField) || [];
const resolvedValues = resolveValuesInArray(value, data, valueField) || [];
return resolvedValues.concat(customValues);
};
/**
* @hidden
*/
const isObjectArray = (values) => {
return isArray(values) && values.every(item => isObject(item));
};
/**
* @hidden
*/
const selectedIndices = (values, data, valueField) => {
const extractedValues = data.map(item => {
return isPresent(item) && isPresent(getter(item, valueField)) ? getter(item, valueField) : item;
});
return values.reduce((arr, item) => {
const value = isPresent(item) && isPresent(getter(item, valueField)) ? getter(item, valueField) : item;
const index = extractedValues.indexOf(value);
if (index !== -1) {
arr.push(index);
}
return arr;
}, []);
};
/**
* @hidden
*/
const getter = (dataItem, field) => {
if (!isPresent(dataItem)) {
return null;
}
if (!isPresent(field) || !isObject(dataItem)) {
return dataItem;
}
// creates a field accessor supporting nested fields processing
const valueFrom = getter$1(field);
return valueFrom(dataItem);
};
/**
* @hidden
*/
const resolveValue = (args) => {
let dataItem;
if (isPresent(args.value)) {
const data = [args.defaultItem, ...args.data];
dataItem = data.find(element => getter(element, args.valueField) === args.value);
return {
dataItem: dataItem,
focused: args.data.indexOf(dataItem),
selected: args.data.indexOf(dataItem)
};
}
else if (args.index) {
dataItem = args.data[args.index];
return {
dataItem: args.data[args.index],
focused: args.index,
selected: args.index
};
}
return {
dataItem: args.defaultItem,
focused: -1,
selected: -1
};
};
/**
* @hidden
*/
const sameCharsOnly = (word, character) => {
for (let idx = 0; idx < word.length; idx++) {
if (word.charAt(idx) !== character) {
return false;
}
}
return true;
};
/**
* @hidden
*/
const shuffleData = (data, splitIndex, defaultItem) => {
let result = data;
if (defaultItem) {
result = [defaultItem].concat(result);
}
return result.slice(splitIndex).concat(result.slice(0, splitIndex));
};
/**
* @hidden
*/
const matchText = (text, word, ignoreCase) => {
if (!isPresent(text)) {
return false;
}
let temp = String(text);
if (ignoreCase) {
temp = temp.toLowerCase();
}
return temp.indexOf(word) === 0;
};
/**
* @hidden
*/
const elementFromPoint = (x, y) => {
if (!isDocumentAvailable()) {
return;
}
return document.elementFromPoint(x, y);
};
/**
* @hidden
*
* Checks whether the passed object has all of the listed properties.
*/
const hasProps = (obj, props) => {
if (!isPresent(obj)) {
return false;
}
return props.every(prop => obj.hasOwnProperty(prop));
};
/**
* @hidden
*
* Checks whether an element is untouched by looking for the ng-untouched css class
*/
const isUntouched = (element) => element.className.includes('ng-untouched');
/**
* @hidden
*/
const noop = (_) => { };
/**
* IE element `matches` polyfill.
* https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
*/
const matches = (element, selector) => {
const matcher = element.matches || element.msMatchesSelector || element.webkitMatchesSelector;
if (!matcher) {
return false;
}
return matcher.call(element, selector);
};
/**
* @hidden
*
* IE element `closest` polyfill.
* https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
*/
const closest = (element, selector) => {
let parent = element;
while (parent !== null && parent.nodeType === 1) {
if (matches(parent, selector)) {
return parent;
}
parent = parent.parentElement || parent.parentNode;
}
return null;
};
/**
* @hidden
*
* Parses a provided value to its type 'number' representation.
* If the parsed value (via Number(value)) is NaN, the provided default value is returned.
* Uses 0 as default value if a second param is not provided.
*/
const parseNumber = (num, defaultValue = 0) => {
const normalizedValue = Number(num);
return isNaN(normalizedValue) ? defaultValue : normalizedValue;
};
/**
* @hidden
*
* Checks whether the passed target element is inside the provided host or popupRef.
*/
const inDropDown = (host, target, popupRef) => {
return host.nativeElement.contains(target) || (popupRef && popupRef.popupElement.contains(target));
};
/**
* @hidden
*
* Calculates the hierarchical level of an item, based on the provided index.
* The result level is zero-based (starts from 0).
*/
const getHierarchicalItemLevel = (index) => {
return (index || '').split('_').length - 1;
};
/**
* @hidden
*
* Retrieves all descendant nodes' lookups which are currently registered in the provided lookup item as a flat array.
*/
const fetchDescendentNodes = (lookup, filterExpression) => {
if (!isPresent(lookup) || lookup.children.length === 0) {
return [];
}
let descendants = lookup.children;
if (isPresent(filterExpression)) {
descendants = descendants.filter(descendent => filterExpression(descendent.item));
}
descendants.forEach(child => descendants = descendants.concat(fetchDescendentNodes(child, filterExpression)));
return descendants;
};
/**
* @hidden
*
* Retrieves the correct value based on the item's level and the provided value field/s.
* Used in the MultiSelectTree component.
*/
const valueFrom = ({ dataItem, index, level }, valueField) => {
const fields = Array.isArray(valueField) ? valueField : [valueField];
// either use the explicitly provided value level, or infer it from the item index
const valueLevel = isPresent(level) ? level : getHierarchicalItemLevel(index);
// fall-back to the last available one, if the current node is in a deeper level
const normalizedLevel = Math.min(valueLevel, fields.length - 1);
const field = fields[normalizedLevel];
return getter$1(field)(dataItem);
};
/**
* @hidden
* Returns the size class based on the component and size input.
*/
const getSizeClass = (component, size) => {
const SIZE_CLASSES = {
'small': `k-${component}-sm`,
'medium': `k-${component}-md`,
'large': `k-${component}-lg`
};
return SIZE_CLASSES[size];
};
/**
* @hidden
* Returns the rounded class based on the rounded input.
*/
const getRoundedClass = (rounded) => {
const ROUNDED_CLASSES = {
'small': 'k-rounded-sm',
'medium': 'k-rounded-md',
'large': 'k-rounded-lg',
'full': 'k-rounded-full'
};
return ROUNDED_CLASSES[rounded];
};
/**
* @hidden
* Return the fillMode class based on the component and fillMode input.
*/
const getFillModeClass = (component, fillMode) => {
const FILLMODE_CLASSES = {
'solid': `k-${component}-solid`,
'flat': `k-${component}-flat`,
'outline': `k-${component}-outline`
};
return FILLMODE_CLASSES[fillMode];
};
/**
* @hidden
*/
const filterAndMap = (arr, predicate, mapper) => arr.reduce((acc, curr) => predicate(curr) ? [...acc, mapper(curr)] : acc, []);
/**
* @hidden
*
* Checks if input is Japanese IME
*/
const isJapanese = (input) => {
const japaneseRegex = /[\u3000-\u303F]|[\u3040-\u309F]|[\u30A0-\u30FF]|[\uFF00-\uFFEF]|[\u4E00-\u9FAF]|[\u2605-\u2606]|[\u2190-\u2195]|\u203B/g;
return japaneseRegex.test(input);
};
/**
* @hidden
*/
const isLetter = (text) => {
const isLetter = /[a-zA-Z]/;
return isLetter.test(text) && text?.length === 1;
};
/**
* @hidden
*/
const getTextField = (field, level) => {
if (isArray(field)) {
return field[level];
}
return field;
};
/**
* @hidden
*/
const getSearchableItems = (treeViewId, element) => {
const nodeSeletor = `kendo-treeview[id='${treeViewId}'] li.k-treeview-item`;
const liElements = Array.from(element.querySelectorAll(nodeSeletor));
return liElements.map((liElement) => {
return { text: liElement.innerText, index: liElement.getAttribute('data-treeindex') };
});
};
/**
* @hidden
*/
const isTruthy = (value) => !!value;
/**
* @hidden
*/
const updateActionSheetAdaptiveAppearance = (actionSheet, windowSize, renderer) => {
const element = actionSheet['element'].nativeElement.querySelector('.k-actionsheet');
const animationContainer = actionSheet['element'].nativeElement.querySelector('.k-child-animation-container');
if (windowSize === 'medium') {
renderer.removeClass(element, 'k-actionsheet-fullscreen');
renderer.addClass(element, 'k-actionsheet-bottom');
renderer.addClass(element, 'k-adaptive-actionsheet');
renderer.removeStyle(animationContainer, 'top');
renderer.removeStyle(animationContainer, 'height');
renderer.setStyle(animationContainer, 'bottom', '0px');
}
else if (windowSize === 'small') {
renderer.removeClass(element, 'k-actionsheet-bottom');
renderer.addClass(element, 'k-actionsheet-fullscreen');
renderer.addClass(element, 'k-adaptive-actionsheet');
renderer.setStyle(animationContainer, 'bottom', '0px');
renderer.setStyle(animationContainer, 'height', '100%');
}
};
/**
* @hidden
*/
const setListBoxAriaLabelledBy = (optionsList, element, renderer) => {
const listBox = optionsList.wrapper.nativeElement.querySelector('kendo-list ul');
const ariaLabel = element.nativeElement.getAttribute('aria-labelledby') || element.nativeElement.getAttribute('data-kendo-label-id');
if (ariaLabel) {
renderer.setAttribute(listBox, 'aria-labelledby', ariaLabel);
}
};
/**
* @hidden
*/
const setActionSheetTitle = (element, actionSheetTitle) => {
const ariaLabel = element.nativeElement.getAttribute('aria-labelledby') || element.nativeElement.getAttribute('data-kendo-label-id');
if (!actionSheetTitle && ariaLabel) {
return document.getElementById(ariaLabel).innerText;
}
return actionSheetTitle;
};
/**
* @hidden
*/
const animationDuration = 300;
/**
* @hidden
*/
class SearchBarComponent {
localization;
injector;
input;
ngZone;
direction;
tagListId;
set readonly(readonly) {
this._readonly = readonly;
if (this._readonly) {
this.renderer.setAttribute(this.input.nativeElement, 'readonly', '');
}
else {
this.renderer.removeAttribute(this.input.nativeElement, 'readonly');
}
}
get readonly() {
return this._readonly;
}
set disabled(disabled) {
this._disabled = disabled;
if (this._disabled) {
this.renderer.setAttribute(this.input.nativeElement, 'disabled', '');
}
else {
this.renderer.removeAttribute(this.input.nativeElement, 'disabled');
}
}
get disabled() {
return this._disabled;
}
set isRequired(isRequired) {
this._isRequired = isRequired;
if (this._isRequired) {
this.renderer.setAttribute(this.input.nativeElement, 'required', '');
}
else {
this.renderer.removeAttribute(this.input.nativeElement, 'required');
}
}
get isRequired() {
return this._isRequired;
}
set isSuggestable(isSuggestable) {
this._isSuggestable = isSuggestable;
this.setAriaAutocomplete();
}
get isSuggestable() {
return this._isSuggestable;
}
set isFilterable(isFilterable) {
this._isFilterable = isFilterable;
this.setAriaAutocomplete();
}
get isFilterable() {
return this._isFilterable;
}
get userInput() {
return this._userInput;
}
set userInput(userInput) {
this._userInput = userInput || "";
}
/**
* @hidden
*/
get formControl() {
const ngControl = this.injector.get(NgControl, null);
return ngControl?.control || null;
}
suggestedText;
/**
* @hidden
*/
set inputAttributes(attributes) {
if (isObjectPresent(this.parsedAttributes)) {
removeHTMLAttributes(this.parsedAttributes, this.renderer, this.input.nativeElement);
}
this._inputAttributes = attributes;
this.parsedAttributes = this.inputAttributes ?
parseAttributes(this.inputAttributes, this.defaultAttributes) :
this.inputAttributes;
this.setInputAttributes();
}
get inputAttributes() {
return this._inputAttributes;
}
id;
activeDescendant;
tabIndex;
isLoading;
ariaControls;
ariaExpanded = null;
get attrAriaInvalid() {
return this.formControl?.invalid ? true : null;
}
set placeholder(text) {
this._placeholder = text || '';
this.setInputSize();
}
get placeholder() {
return this._placeholder;
}
role = 'combobox';
get dir() {
return this.direction;
}
valueChange = new EventEmitter();
onBlur = new EventEmitter();
onFocus = new EventEmitter();
onClick = new EventEmitter();
onNavigate = new EventEmitter();
get value() {
return this.input.nativeElement.value;
}
_isRequired;
_readonly;
_disabled;
_userInput = "";
_previousValue = "";
_placeholder = "";
_isSuggestable = false;
_isFilterable = false;
renderer;
subs = new Subscription();
_inputAttributes;
parsedAttributes = {};
get defaultAttributes() {
return {
id: this.id,
disabled: this.disabled ? '' : null,
readonly: this.readonly ? '' : null,
placeholder: this.placeholder,
tabIndex: this.tabIndex,
tabindex: this.tabIndex,
dir: this.direction,
required: this.isRequired ? '' : null,
'aria-haspopup': 'listbox',
'aria-expanded': this.ariaExpanded,
'aria-controls': this.ariaControls,
'aria-activedescendant': this.activeDescendant,
'aria-busy': this.isLoading,
'aria-invalid': this.formControl?.invalid
};
}
get mutableAttributes() {
return {
autocomplete: 'off',
role: this.role,
'aria-describedby': this.tagListId
};
}
constructor(localization, renderer, injector, input, ngZone) {
this.localization = localization;
this.injector = injector;
this.input = input;
this.ngZone = ngZone;
this.direction = localization.rtl ? 'rtl' : 'ltr';
this.renderer = renderer;
this.renderer.addClass(this.input.nativeElement, 'k-input-inner');
this.renderer.setAttribute(this.input.nativeElement, 'aria-haspopup', 'listbox');
this.renderer.setAttribute(this.input.nativeElement, 'autocomplete', 'off');
}
ngOnInit() {
this.subs.add(this.localization
.changes.subscribe(({ rtl }) => this.direction = rtl ? 'rtl' : 'ltr'));
}
ngOnChanges(changes) {
if (!isDocumentAvailable()) {
return;
}
let previousUserInput;
if (this.input && (changes.userInput || changes.suggestedText)) {
if (changes.userInput && changes.userInput.previousValue) {
if (this._previousValue === changes.userInput.previousValue) {
previousUserInput = this._previousValue;
}
else {
previousUserInput = changes.userInput.currentValue || "";
}
}
else {
previousUserInput = this._previousValue;
}
const caretStart = this.input.nativeElement.selectionStart;
const caretAtEnd = previousUserInput.length === caretStart;
this.writeInputValue(this.suggestedText ? combineStr(this.userInput, this.suggestedText) : this.userInput);
if (this.suggestedText) {
this.setInputSelection(this.userInput.length, this.suggestedText.length);
}
else if (isSafari(navigator.userAgent) && !caretAtEnd) {
this.setInputSelection(caretStart, this.userInput.length);
}
else if (caretAtEnd) {
this.setInputSelection(this.userInput.length, this.userInput.length);
}
else {
this.setInputSelection(caretStart, caretStart);
}
this._previousValue = this.userInput;
}
}
ngAfterViewInit() {
this.subs.add(this.input.nativeElement.addEventListener('input', (event) => this.handleInput(event)));
this.subs.add(this.input.nativeElement.addEventListener('focus', (event) => this.handleFocus(event)));
this.subs.add(this.input.nativeElement.addEventListener('blur', (event) => this.handleBlur(event)));
this.subs.add(this.input.nativeElement.addEventListener('keydown', (event) => this.handleKeydown(event)));
}
ngOnDestroy() {
this.subs.unsubscribe();
}
writeInputValue(text) {
if (isDocumentAvailable()) {
this.renderer.setProperty(this.input.nativeElement, 'value', text);
}
}
setInputSelection(start, end) {
if (isDocumentAvailable() && this.input.nativeElement === document.activeElement) {
try {
this.input.nativeElement.setSelectionRange(start, end);
}
catch (e) {
//Make sure that the element is in the DOM before you invoke its methods
}
}
}
setAriaAutocomplete() {
if (this.isFilterable) {
this.renderer.setAttribute(this.input.nativeElement, 'aria-autocomplete', 'list');
}
if (this.isSuggestable) {
this.renderer.setAttribute(this.input.nativeElement, 'aria-autocomplete', 'inline');
}
if (this.isFilterable && this.isSuggestable) {
this.renderer.setAttribute(this.input.nativeElement, 'aria-autocomplete', 'both');
}
if (!this.isFilterable && !this.isSuggestable) {
this.renderer.removeAttribute(this.input.nativeElement, 'aria-autocomplete');
}
}
handleInput(event) {
const target = event.target;
const isBrowserSafari = isSafari(navigator.userAgent);
const value = isBrowserSafari && isJapanese(target.value) ? event.data : target.value;
if (value !== this.userInput) {
this._previousValue = value;
this.valueChange.emit(value);
}
}
handleFocus(event) {
this.onFocus.emit(event);
}
handleBlur(event) {
this.onBlur.emit(event);
}
handleKeydown(event) {
const keyCode = event.keyCode;
const keys = [Keys.ArrowUp, Keys.ArrowDown, Keys.ArrowLeft, Keys.ArrowRight, Keys.Enter,
Keys.Escape, Keys.Delete, Keys.Backspace, Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp];
if (keys.indexOf(keyCode) > -1) {
this.onNavigate.emit(event);
}
}
focus() {
if (isDocumentAvailable()) {
this.input.nativeElement.focus();
}
}
blur() {
if (isDocumentAvailable()) {
this.input.nativeElement.blur();
}
}
setInputSize() {
const lengthOf = x => x ? x.length : 0;
const input = this.input.nativeElement;
const placeholderLength = lengthOf(this.placeholder);
const textLength = lengthOf(this.value);
const size = Math.max(placeholderLength, textLength, 1);
this.renderer.setAttribute(input, 'size', size.toString());
}
setInputAttributes() {
const attributesToRender = Object.assign({}, this.mutableAttributes, this.parsedAttributes);
setHTMLAttributes(attributesToRender, this.renderer, this.input.nativeElement, this.ngZone);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SearchBarComponent, deps: [{ token: i1.LocalizationService }, { token: i0.Renderer2 }, { token: i0.Injector }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SearchBarComponent, isStandalone: true, selector: "input[kendoSearchbar]", inputs: { tagListId: "tagListId", readonly: "readonly", disabled: "disabled", isRequired: "isRequired", isSuggestable: "isSuggestable", isFilterable: "isFilterable", userInput: "userInput", suggestedText: "suggestedText", inputAttributes: "inputAttributes", id: "id", activeDescendant: "activeDescendant", tabIndex: "tabIndex", isLoading: "isLoading", ariaControls: "ariaControls", ariaExpanded: "ariaExpanded", placeholder: "placeholder" }, outputs: { valueChange: "valueChange", onBlur: "onBlur", onFocus: "onFocus", onClick: "onClick", onNavigate: "onNavigate" }, host: { properties: { "attr.id": "this.id", "attr.aria-activedescendant": "this.activeDescendant", "attr.tabindex": "this.tabIndex", "attr.aria-busy": "this.isLoading", "attr.aria-controls": "this.ariaControls", "attr.aria-expanded": "this.ariaExpanded", "attr.aria-invalid": "this.attrAriaInvalid", "attr.placeholder": "this.placeholder", "attr.role": "this.role", "attr.dir": "this.dir" } }, usesOnChanges: true, ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SearchBarComponent, decorators: [{
type: Component,
args: [{
selector: 'input[kendoSearchbar]',
template: ``,
standalone: true,
imports: [EventsOutsideAngularDirective]
}]
}], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i0.Renderer2 }, { type: i0.Injector }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { tagListId: [{
type: Input
}], readonly: [{
type: Input
}], disabled: [{
type: Input
}], isRequired: [{
type: Input
}], isSuggestable: [{
type: Input
}], isFilterable: [{
type: Input
}], userInput: [{
type: Input
}], suggestedText: [{
type: Input
}], inputAttributes: [{
type: Input
}], id: [{
type: HostBinding,
args: ['attr.id']
}, {
type: Input
}], activeDescendant: [{
type: HostBinding,
args: ['attr.aria-activedescendant']
}, {
type: Input
}], tabIndex: [{
type: HostBinding,
args: ['attr.tabindex']
}, {
type: Input
}], isLoading: [{
type: HostBinding,
args: ['attr.aria-busy']
}, {
type: Input
}], ariaControls: [{
type: HostBinding,
args: ['attr.aria-controls']
}, {
type: Input
}], ariaExpanded: [{
type: HostBinding,
args: ['attr.aria-expanded']
}, {
type: Input
}], attrAriaInvalid: [{
type: HostBinding,
args: ['attr.aria-invalid']
}], placeholder: [{
type: HostBinding,
args: ['attr.placeholder']
}, {
type: Input
}], role: [{
type: HostBinding,
args: ['attr.role']
}], dir: [{
type: HostBinding,
args: ['attr.dir']
}], valueChange: [{
type: Output
}], onBlur: [{
type: Output
}], onFocus: [{
type: Output
}], onClick: [{
type: Output
}], onNavigate: [{
type: Output
}] } });
/**
* Renders the list item content. To define the item template, nest an `<ng-template>` tag
* with the `kendo<ComponentName>ItemTemplate` directive inside the component tag. The template context is
* set to the current component. To get a reference to the current data item, use the `let-dataItem` directive.
*
* - [Using `ItemTemplate` with the AutoComplete]({% slug templates_autocomplete %}#toc-item-template)
* - [Using `ItemTemplate` with the ComboBox]({% slug templates_combobox %}#toc-item-template)
* - [Using `ItemTemplate` with the DropDownList]({% slug templates_ddl %}#toc-item-template)
* - [Using `ItemTemplate` with the MultiSelect]({% slug templates_multiselect %}#toc-item-template)
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-combobox [data]="listItems">
* <ng-template kendoComboBoxItemTemplate let-dataItem>
* <span>{{dataItem}} option</span>
* </ng-template>
* </kendo-combobox>
* `
* })
* class AppComponent {
* public listItems: Array<string> = ["Item 1", "Item 2", "Item 3", "Item 4"];
* }
* ```
*/
class ItemTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ItemTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ItemTemplateDirective, isStandalone: true, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ItemTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
/**
* Renders the header content of the list. To define the header template, nest an `<ng-template>` tag
* with the `kendo<ComponentName>HeaderTemplate` directive inside the component tag.
*
* - [Using `HeaderTemplate` with the AutoComplete]({% slug templates_autocomplete %}#toc-header-template)
* - [Using `HeaderTemplate` with the ComboBox]({% slug templates_combobox %}#toc-header-template)
* - [Using `HeaderTemplate` with the MultiColumnComboBox]({% slug templates_multicolumncombobox %}#toc-header-template)
* - [Using `HeaderTemplate` with the DropDownList]({% slug templates_ddl %}#toc-header-template)
* - [Using `HeaderTemplate` with the DropDownTree]({% slug templates_ddt %}#toc-header-template)
* - [Using `HeaderTemplate` with the MultiSelect]({% slug templates_multiselect %}#toc-header-template)
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-combobox [data]="listItems">
* <ng-template kendoComboBoxHeaderTemplate>
* <h4>Header template</h4>
* </ng-template>
* </kendo-combobox>
* `
* })
* class AppComponent {
* public listItems: Array<string> = ["Item 1", "Item 2", "Item 3", "Item 4"];
* }
* ```
*/
class HeaderTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeaderTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HeaderTemplateDirective, isStandalone: true, selector: "[kendoDropDownListHeaderTemplate],[kendoComboBoxHeaderTemplate],[kendoDropDownTreeHeaderTemplate],[kendoMultiColumnComboBoxHeaderTemplate],[kendoAutoCompleteHeaderTemplate],[kendoMultiSelectHeaderTemplate],[kendoMultiSelectTreeHeaderTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeaderTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDropDownListHeaderTemplate],[kendoComboBoxHeaderTemplate],[kendoDropDownTreeHeaderTemplate],[kendoMultiColumnComboBoxHeaderTemplate],[kendoAutoCompleteHeaderTemplate],[kendoMultiSelectHeaderTemplate],[kendoMultiSelectTreeHeaderTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
/**
* Renders the footer content of the list. To define the footer template, nest an `<ng-template>` tag
* with the `kendo<ComponentName>FooterTemplate` directive inside the component tag.
*
* - [Using `FooterTemplate` with the AutoComplete]({% slug templates_autocomplete %}#toc-footer-template)
* - [Using `FooterTemplate` with the ComboBox]({% slug templates_combobox %}#toc-footer-template)
* - [Using `FooterTemplate` with the MultiColumnComboBox]({% slug templates_multicolumncombobox %}#toc-footer-template)
* - [Using `FooterTemplate` with the DropDownList]({% slug templates_ddl %}#toc-footer-template)
* - [Using `FooterTemplate` with the DropDownTree]({% slug templates_ddt %}#toc-footer-template)
* - [Using `FooterTemplate` with the MultiSelect]({% slug templates_multiselect %}#toc-footer-template)
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-combobox [data]="listItems">
* <ng-template kendoComboBoxFooterTemplate>
* <h4>Footer template</h4>
* </ng-template>
* </kendo-combobox>
* `
* })
* class AppComponent {
* public listItems: Array<string> = ["Item 1", "Item 2", "Item 3", "Item 4"];
* }
* ```
*/
class FooterTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FooterTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FooterTemplateDirective, isStandalone: true, selector: "[kendoDropDownListFooterTemplate],[kendoComboBoxFooterTemplate],[kendoDropDownTreeFooterTemplate],[kendoMultiColumnComboBoxFooterTemplate],[kendoAutoCompleteFooterTemplate],[kendoMultiSelectFooterTemplate],[kendoMultiSelectTreeFooterTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FooterTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDropDownListFooterTemplate],[kendoComboBoxFooterTemplate],[kendoDropDownTreeFooterTemplate],[kendoMultiColumnComboBoxFooterTemplate],[kendoAutoCompleteFooterTemplate],[kendoMultiSelectFooterTemplate],[kendoMultiSelectTreeFooterTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
/**
* Renders the group header content. To define the group template, nest an `<ng-template>` tag
* with the `kendo<ComponentName>GroupTemplate` directive inside the component tag. The template context is
* set to the current component. To get a reference to the current data item, use the `let-groupName` directive.
*
* - [Using `GroupTemplate` with the AutoComplete]({% slug templates_autocomplete %}#toc-group-header-template)
* - [Using `GroupTemplate` with the ComboBox]({% slug templates_combobox %}#toc-group-header-template)
* - [Using `GroupTemplate` with the MultiColumnComboBox]({% slug templates_multicolumncombobox %}#toc-group-header-template)
* - [Using `GroupTemplate` with the DropDownList]({% slug templates_ddl %}#toc-group-header-template)
* - [Using `GroupTemplate` with the MultiSelect]({% slug templates_multiselect %}#toc-group-header-template)
*
* @example
* ```ts
* import { groupBy } from '@progress/kendo-data-query';
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-combobox [data]="groupedData" textField="name" valueField="name">
* <ng-template kendoComboBoxGroupTemplate let-groupName>
* <span>Food type: {{groupName}} option</span>
* </ng-template>
* </kendo-combobox>
* `
* })
* class AppComponent {
* public data = [
* { name: "Pork", category: "Food", subcategory: "Meat" },
* { name: "Pepper", category: "Food", subcategory: "Vegetables" },
* { name: "Beef", category: "Food", subcategory: "Meat" }
* ];
* public groupedData = groupBy(this.data, [{field: "subcategory"}]);
* }
* ```
*/
class GroupTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: GroupTemplateDirective, isStandalone: true, selector: "[kendoDropDownListGroupTemplate],[kendoComboBoxGroupTemplate],[kendoMultiColumnComboBoxGroupTemplate],[kendoAutoCompleteGroupTemplate],[kendoMultiSelectGroupTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDropDownListGroupTemplate],[kendoComboBoxGroupTemplate],[kendoMultiColumnComboBoxGroupTemplate],[kendoAutoCompleteGroupTemplate],[kendoMultiSelectGroupTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
/**
* Renders the fixed group header content. To define the fixed group template, nest an `<ng-template>` tag
* with the `kendo<ComponentName>FixedGroupTemplate` directive inside the component tag. The template context is
* set to the current component. To get a reference to the current data item, use the `let-groupName` directive.
*
* - [Using `FixedGroupTemplate` with the AutoComplete]({% slug templates_autocomplete %}#toc-fixed-group-header-template)
* - [Using `FixedGroupTemplate` with the ComboBox]({% slug templates_combobox %}#toc-fixed-group-header-template)
* - [Using `FixedGroupTemplate` with the MultiColumnComboBox]({% slug templates_multicolumncombobox %}#toc-fixed-group-header-template)
* - [Using `FixedGroupTemplate` with the DropDownList]({% slug templates_ddl %}#toc-fixed-group-header-template)
* - [Using `FixedGroupTemplate` with the MultiSelect]({% slug templates_multiselect %}#toc-fixed-group-header-template)
*
* @example
* ```ts
* import { groupBy } from '@progress/kendo-data-query';
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-combobox [data]="groupedData" textField="name" valueField="name">
* <ng-template kendoComboBoxFixedGroupTemplate let-groupName>
* <span>Food type: {{groupName}} option</span>
* </ng-template>
* </kendo-combobox>
* `
* })
* class AppComponent {
* public data = [
* { name: "Pork", category: "Food", subcategory: "Meat" },
* { name: "Pepper", category: "Food", subcategory: "Vegetables" },
* { name: "Beef", category: "Food", subcategory: "Meat" }
* ];
* public groupedData = groupBy(this.data, [{field: "subcategory"}]);
* }
* ```
*/
class FixedGroupTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FixedGroupTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FixedGroupTemplateDirective, isStandalone: true, selector: "[kendoDropDownListFixedGroupTemplate],[kendoComboBoxFixedGroupTemplate],[kendoMultiColumnComboBoxFixedGroupTemplate],[kendoAutoCompleteFixedGroupTemplate],[kendoMultiSelectFixedGroupTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FixedGroupTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDropDownListFixedGroupTemplate],[kendoComboBoxFixedGroupTemplate],[kendoMultiColumnComboBoxFixedGroupTemplate],[kendoAutoCompleteFixedGroupTemplate],[kendoMultiSelectFixedGroupTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
/**
* @hidden
*/
class DataService {
grouped = false;
groupIndices = [];
view;
_data;
_flatData;
set data(data) {
this._data = data;
this.grouped = this.isGrouped(data);
if (this.grouped) {
this.groupIndices = this.getGroupIndices(data);
this._flatData = this.flatten(data);
}
}
get data() {
if (this.grouped) {
return this._flatData;
}
return this._data;
}
/**
* @hidden
* Used to get the actual items count, i.e. excluding the header items in case of grouping.
*/
get itemsCount() {
if (!isPresent(this.data) || this.data.length === 0) {
return 0;
}
const items = this.grouped ? this._flatData.filter(item => !item.header) : this.data;
return items.length;
}
/**
* @hidden
* Used to determine if the component received grouped data.
*/
isGrouped(data) {
// GroupResult { aggregates: AggregateResult, field: string, items: object[], value: any }
// https://www.telerik.com/kendo-angular-ui/components/dataquery/api/GroupResult/
return (isPresent(data) && data.length !== 0) && isPresent(data[0]) && hasProps(data[0], ['aggregates', 'field', 'items', 'value']);
}
/**
* @hidden
* Used to calculate the last item index of each group.
*/
getGroupIndices(data) {
const groupIndices = [];
for (let i = 0; i <= data.length - 1; i++) {
groupIndices[i] = (groupIndices[i - 1] || 0) + data[i].items.length;
}
return groupIndices;
}
/**
* @hidden
* Used to get a flat array containing all items matching certain criteria.
*/
filter(predicate) {
let result = [];
if (this.isGrouped(this.data)) {
for (let i = 0; i <= this.groupIndices.length - 1; i++) {
const matches = this.data[i].items.filter(predicate);
if (matches) {
result = result.concat(matches);
}
}
}
else {
result = this.data.filter(predicate);
}
return result;
}
/**
* @hidden
* Used to get the index of a given data item.
*/
indexOf(item, startFrom = 0) {
let predicate = (element) => {
return element === item;
};
if (this.grouped) {
predicate = (element) => {
return element.value === item;
};
}
return this.findIndex(predicate, startFrom);
}
/**
* @hidden
* Used to get the index of a data item based on an expression.
*/
findIndex(predicate, startFrom = 0) {
let index = -1;
if (this.grouped) {
const data = this._flatData.filter(item => !item.header && item.offsetIndex >= startFrom);
index = data.findIndex(predicate);
index = data[index] ? data[index].offsetIndex : -1;
}
else {
const data = this.data.slice(startFrom);
const itemIndex = data.findIndex(predicate);
index = itemIndex !== -1 ? itemIndex + startFrom : -1;
}
return index;
}
/**
* @hidden
* Used to get the closest group header prior to an item index.
*/
closestGroup(index) {
for (let i = index; i >= 0; i--) {
if (this._flatData[i].header) {
return this._flatData[i];
}
}
}
/**
* @hidden
* Used to get the first item matching the criteria.
*/
find(predicate) {
const index = this.findIndex(predicate);
return this.itemAt(index);
}
/**
* @hidden
* Used to get the true index in a flattened data array.
*/
flatIndex(index) {
if (this.itemsCount === 0) {
return -1;
}
if (this.grouped) {
const match = this._flatData.find((item) => !item.header && item.offsetIndex === index);
if (match) {
return match.index;
}
}
else {
return index;
}
return -1;
}
/**
* @hidden
* Used to get the item at the provided index.
*/
itemAt(index) {
let dataItem;
if (this.itemsCount === 0) {
return dataItem;
}
if (this.grouped) {
const match = this._flatData.find((item) => !item.header && item.offsetIndex === index);
if (match) {
dataItem = match.value;
}
}
else {
dataItem = this.data[index];
}
return dataItem;
}
/**
* @hidden
* Used to get the group at the provided index.
*/
groupAt(index) {
if (this.itemsCount === 0 || !this.isGrouped) {
return;
}
return this._flatData.find((item) => item.header && item.index === index);
}
/**
* @hidden
* Used to get all group items indices.
*/
groupItemsIndices() {
if (this.isGrouped) {
return filterAndMap(this.data, item => item.header, mappedItem => mappedItem.index);
}
return [];
}
/**
* @hidden
* Used to get the field by which the data is grouped.
*/
groupField() {
if (this.itemsCount === 0 || !this.isGrouped) {
return null;
}
return this._data[0].field;
}
/**
* @hidden
* Used to get the group to which a dataItem belongs.
*/
itemGroup(item) {
if (!item || this.itemsCount === 0 || !this.isGrouped) {
return;
}
const fieldName = this.groupField();
if (fieldName) {
return getter(item, fieldName);
}
}
flatten(data, group = undefined, offset = 0, groupIndex = 0) {
let flat = [];
if (isPresent(group)) {
flat.push({
header: true,
groupIndex: groupIndex,
index: groupIndex + offset,
offsetIndex: groupIndex,
value: group
});
}
for (let i = 0; i < data.length; i++) {
let result = [];
if (data[i].items) {
result = this.flatten(data[i].items, data[i].value, offset, i);
offset = offset + data[i].items.length;
}
else {
result.push({
header: false,
groupIndex: groupIndex,
index: groupIndex + offset + i + 1,
offsetIndex: offset + i,
value: data[i]
});
}
flat = flat.concat(result);
}
return flat;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataService, decorators: [{
type: Injectable
}] });
/**
* @hidden
*/
class DisabledItemsService {
dataService;
defaultItem;
itemDisabled = null;
constructor(dataSe