UNPKG

@progress/kendo-angular-dropdowns

Version:

A wide variety of native Angular dropdown components including AutoComplete, ComboBox, DropDownList, DropDownTree, MultiColumnComboBox, MultiSelect, and MultiSelectTree

969 lines (966 loc) 38.6 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Component, Input, Output, EventEmitter, ViewChildren, QueryList, ElementRef, ViewChild, ChangeDetectorRef, NgZone, Renderer2 } from '@angular/core'; import { ResizeSensorComponent, TemplateContextDirective, isChanged, replaceMessagePlaceholder } from '@progress/kendo-angular-common'; import { LocalizationService } from '@progress/kendo-angular-l10n'; import { ListItemDirective } from './list-item.directive'; import { ItemTemplateDirective } from './templates/item-template.directive'; import { GroupTemplateDirective } from './templates/group-template.directive'; import { FixedGroupTemplateDirective } from './templates/fixed-group-template.directive'; import { isPresent, getter, closest, getSizeClass, getRoundedClass } from './util'; import { SelectionService } from './selection/selection.service'; import { fromEvent, merge } from 'rxjs'; import { map, tap, auditTime, switchMap, take } from 'rxjs/operators'; import { DisabledItemsService } from './disabled-items/disabled-items.service'; import { DataService } from './data.service'; import { NavigationAction } from './navigation/navigation-action'; import { SelectableDirective } from './selection/selectable.directive'; import { NgStyle, NgClass } from '@angular/common'; import { CustomItemTemplateDirective } from './templates/custom-item-template.directive'; import * as i0 from "@angular/core"; import * as i1 from "./data.service"; import * as i2 from "./selection/selection.service"; import * as i3 from "./disabled-items/disabled-items.service"; import * as i4 from "@progress/kendo-angular-l10n"; /** * @hidden */ export class ListComponent { dataService; wrapper; selectionService; disabledItemsService; cdr; zone; renderer; localization; selected = []; focused = -1; textField; valueField; height; template; groupTemplate; fixedGroupTemplate; show = true; id; optionPrefix; multipleSelection = false; virtual; type = 'list'; checkboxes = { enabled: false }; ariaLive; isMultiselect; isActionSheetExpanded; showStickyHeader; rowWidth; customItemTemplate; text; allowCustom; defaultItem; set data(data) { this._data = data[0]?.header ? data.slice(0) : data; if (this.dataService.grouped) { if (this.virtual) { const firstGroupItem = this.dataService.data.find(item => item.header && item.groupIndex === this.data[0].groupIndex); if (!this.data[0].header) { this._data = [firstGroupItem, ...this._data.slice(1)]; } } this.groupedData = this._data.filter(item => item?.header); this.groupedData.forEach(group => { group.items = this._data.filter(item => !item.header && item.groupIndex === group.groupIndex); }); } } get data() { return this._data; } set size(size) { if (this.type === 'list') { this.renderer.removeClass(this.wrapper.nativeElement, getSizeClass('list', this.size)); if (size) { this.renderer.addClass(this.wrapper.nativeElement, getSizeClass('list', size)); } this._size = size; } } get size() { return this._size; } groupedData; rounded = 'medium'; onClick = new EventEmitter(); pageChange = new EventEmitter(); listResize = new EventEmitter(); popupListScroll = new EventEmitter(); items; content; list; virtualContainer; currentGroup; startFrom = 0; lastLoaded = 0; lastScrollTop = 0; listContentClass; listClass; listItemClass; listVirtualClass; listGroupStickyHeaderClass; listGroupStickyHeaderTextClass; listGroupItemClass; listGroupItemTextClass; scrollToFocused = false; _data; scrollSubscription; selectSubscription; _size = 'medium'; get pageSize() { if (this.virtual.pageSize) { return this.virtual.pageSize; } const size = Math.round(this.height / this.virtual.itemHeight); return size; } get scrollHeight() { return this.virtual.total * this.virtual.itemHeight; } get overflowY() { if (isPresent(this.virtual)) { const overflow = this.hasVirtualScrollbar() ? 'scroll' : 'hidden'; return overflow; } } /** * @hidden */ get useCustomValueText() { const localizationMsg = this.localization.get('useCustomValueText'); return replaceMessagePlaceholder(localizationMsg, 'customValue', this.text); } /** * @hidden */ get checkboxClasses() { return `${this.size ? getSizeClass('checkbox', this.size) : ''} ${this.rounded ? getRoundedClass(this.rounded) : ''}`; } /* tslint:disable:member-ordering */ constructor(dataService, wrapper, selectionService, disabledItemsService, cdr, zone, renderer, localization) { this.dataService = dataService; this.wrapper = wrapper; this.selectionService = selectionService; this.disabledItemsService = disabledItemsService; this.cdr = cdr; this.zone = zone; this.renderer = renderer; this.localization = localization; this.selectSubscription = merge(this.selectionService.onSelect.pipe(map((args) => args.indices[0])), this.selectionService.onFocus) .pipe( // handle only the very last onSelect/onFocus emission switchMap(event => this.zone.onStable.pipe(take(1), map(() => event)))) .subscribe(this.scrollToItem.bind(this)); this.prepareClasses(); } ngOnChanges(changes) { if (isChanged('data', changes, false)) { if (this.lastLoaded <= 0) { this.lastLoaded = this.data.length - 1; this.scrollToFocused = !changes['data'].isFirstChange(); } this.setOverflow(); } if (isChanged('virtual', changes, false)) { this.setOverflow(); } if (isChanged('type', changes, false)) { this.prepareClasses(); } } ngAfterViewInit() { this.setComponentClasses(); this.zone.runOutsideAngular(() => { this.scrollSubscription = fromEvent(this.content.nativeElement, "scroll").pipe(auditTime(100), tap(this.prefetchData.bind(this)), tap(this.findCurrentGroup.bind(this))).subscribe(() => { this.lastScrollTop = this.content.nativeElement.scrollTop; }); }); this.setOverflow(); } ngAfterViewChecked() { if (this.virtual) { this.positionItems(); } if (this.items && this.scrollToFocused) { this.scrollToFocused = false; const scrollTarget = this.items.length && this.selectionService.focused === -1 ? 0 : this.selectionService.focused; this.scrollToItem(scrollTarget); } if (this.dataService.grouped) { this.findCurrentGroup(); } } ngOnDestroy() { this.selectSubscription.unsubscribe(); if (this.scrollSubscription) { this.scrollSubscription.unsubscribe(); } } onCheckedChange(e, index) { const isChecked = e.target['checked']; if (isChecked && !this.selectionService.isSelected(index)) { this.selectionService.add(index); } if (!isChecked && this.selectionService.isSelected(index)) { this.selectionService.deselect(index); } } prepareClasses() { if (this.type === 'list') { this.listContentClass = 'k-list-content'; this.listClass = 'k-list-ul'; this.listItemClass = 'k-list-item'; this.listVirtualClass = 'k-virtual-list'; this.listGroupStickyHeaderClass = 'k-list-group-sticky-header'; this.listGroupStickyHeaderTextClass = 'k-list-header-text'; this.listGroupItemClass = 'k-list-group-item'; this.listGroupItemTextClass = 'k-list-item-text'; } else { this.listContentClass = 'k-table-body k-table-scroller'; this.listClass = 'k-table k-table-list'; this.listItemClass = 'k-table-row'; this.listVirtualClass = 'k-virtual-table'; this.listGroupStickyHeaderClass = 'k-table-group-sticky-header'; this.listGroupStickyHeaderTextClass = 'k-table-th'; this.listGroupItemClass = 'k-table-group-row'; this.listGroupItemTextClass = 'k-table-th'; } } isChecked(index) { const normalizedIndex = this.virtual ? index + this.virtual.skip : index; return this.selectionService.isSelected(normalizedIndex); } firstVisibleItem() { const content = this.content.nativeElement; const rect = content.getBoundingClientRect(); // IE9 hack const disabled = Array.prototype.slice.call(content.querySelectorAll(".k-disabled")); // This is a workaround for finding elements with pointer-events: none; disabled.forEach((el) => this.renderer.setStyle(el, "pointer-events", "auto")); const item = document.elementFromPoint(rect.left + 1, rect.top + 1); disabled.forEach((el) => this.renderer.setStyle(el, "pointer-events", "none")); // return the closest `li` item to cover the custom template scenario return closest(item, 'li'); } findCurrentGroup() { if (!this.dataService.grouped) { this.currentGroup = undefined; return; } const item = this.firstVisibleItem(); if (item) { let index; if (item.getAttribute("role") === "presentation") { index = parseInt(item.getAttribute("group-index"), 10); this.currentGroup = this.dataService.groupAt(index)?.value; } else { index = parseInt(item.getAttribute("index"), 10); this.currentGroup = this.dataService.itemGroup(this.dataService.itemAt(index)); } } else { this.currentGroup = undefined; } this.cdr.detectChanges(); } prefetchData() { if (!this.virtual) { return; } const visibleItems = Math.trunc(this.content.nativeElement.clientHeight / this.virtual.itemHeight); const offsetY = this.content.nativeElement.scrollTop; const start = Math.trunc(offsetY / this.virtual.itemHeight); const down = offsetY > this.lastScrollTop; const nextPage = (start + visibleItems >= this.lastLoaded) && this.lastLoaded < this.virtual.total - 1; const leftOver = this.pageSize - (this.lastLoaded - this.startFrom); const prevPage = this.lastLoaded - this.pageSize + visibleItems >= start - leftOver; if (down && nextPage) { this.changePage(start); } if (!down && prevPage) { this.changePage(start - this.pageSize + visibleItems + 1); } } changePage(start) { this.zone.run(() => { let end = this.pageSize + start; if (end > this.virtual.total) { start--; end = this.virtual.total; } if (start < 0) { start = 0; } this.startFrom = start; this.lastLoaded = end; this.pageChange.emit({ skip: start, take: this.pageSize }); }); } index(groupIndex, itemIndex) { return groupIndex > 0 ? (this.dataService.groupIndices[groupIndex - 1] + itemIndex) : itemIndex; } getText(dataItem) { return getter(dataItem, this.textField); } getValue(dataItem) { return getter(dataItem, this.valueField); } generateGroupId(dataItem) { return `${this.optionPrefix}-${dataItem.groupIndex}-${dataItem.value.toString().split(' ').join('')}`; } isDisabled(index) { if (isPresent(this.virtual) && !this.dataService.grouped) { index += this.virtual.skip; } return this.disabledItemsService.isIndexDisabled(index); } isAltRow(index) { return this.type === 'dropdowngrid' && index % 2 !== 0; } scrollToItem(index) { let flatIndex = index; if (this.dataService.grouped) { // takes into account the group header items flatIndex = this.dataService.flatIndex(index); } if (this.virtual && flatIndex > -1) { this.scrollToIndex(flatIndex); return; } const items = this.items.toArray(); if (isPresent(items[flatIndex]) && flatIndex !== -1) { this.scroll(items[flatIndex].element); } } scrollWithOnePage(action) { const content = this.content.nativeElement; const contentOffsetHeight = content.clientHeight; if (action === NavigationAction.PageDown) { content.scrollTop += contentOffsetHeight; } else if (action === NavigationAction.PageUp) { content.scrollTop -= contentOffsetHeight; } } scrollToIndex(index) { const content = this.content.nativeElement; let contentScrollTop = content.scrollTop; const itemOffsetTop = index * this.virtual.itemHeight; const itemOffsetHeight = this.virtual.itemHeight; const contentOffsetHeight = content.clientHeight; const bottomDistance = itemOffsetTop + itemOffsetHeight; if (contentScrollTop > itemOffsetTop) { contentScrollTop = itemOffsetTop; } else if (bottomDistance > (contentScrollTop + contentOffsetHeight)) { contentScrollTop = (bottomDistance - contentOffsetHeight); } content.scrollTop = contentScrollTop; } scroll(item) { if (!item) { return; } const nativeElement = item.nativeElement; const content = this.content.nativeElement; const itemOffsetTop = nativeElement.offsetTop; const itemOffsetHeight = nativeElement.offsetHeight; let contentScrollTop = content.scrollTop; const contentOffsetHeight = content.clientHeight; const bottomDistance = itemOffsetTop + itemOffsetHeight; if (contentScrollTop > itemOffsetTop) { contentScrollTop = itemOffsetTop; } else if (bottomDistance > (contentScrollTop + contentOffsetHeight)) { contentScrollTop = (bottomDistance - contentOffsetHeight); } content.scrollTop = contentScrollTop; } /** * Indicates whether a scrollbar is currently rendered in the list. */ hasScrollbar() { if (!(isPresent(this.items) && this.items.length && isPresent(this.list) && isPresent(this.content))) { return false; } const hasVirtualScroll = isPresent(this.virtual) && this.hasVirtualScrollbar(); return hasVirtualScroll || this.list.nativeElement.scrollHeight > this.content.nativeElement.offsetHeight; } isItemSelected(index) { return this.selectionService.isSelected(index) || null; } get isDisabledDefaultItem() { return this.disabledItemsService.isItemDisabled(this.defaultItem); } getDefaultItemText() { return getter(this.defaultItem, this.textField); } /** * Sets the list's content overflow (hides/shows scrollbar) */ setOverflow() { if (this.virtual) { const overflow = this.hasVirtualScrollbar() ? 'scroll' : 'hidden'; this.renderer.setStyle(this.content.nativeElement, 'overflow-y', overflow); } } /** * Indicates whether the scrollbar should be visible in virtual mode. */ hasVirtualScrollbar() { const contentOffsetHeight = this.content.nativeElement.offsetHeight; const virtualOffsetHeight = this.virtualContainer && this.virtualContainer.nativeElement.offsetHeight; return this.virtualContainer && virtualOffsetHeight > contentOffsetHeight; } positionItems() { this.items.forEach((item, index) => { const offsetY = (index + this.startFrom) * this.virtual.itemHeight; this.renderer.setStyle(item.element.nativeElement, "transform", `translateY(${offsetY}px`); }); } setComponentClasses() { if (this.type === 'list') { this.renderer.addClass(this.wrapper.nativeElement, 'k-list'); if (this.size) { this.renderer.addClass(this.wrapper.nativeElement, getSizeClass('list', this.size)); } } if (this.type === 'dropdowngrid') { this.renderer.setStyle(this.wrapper.nativeElement, 'overflow-y', 'scroll'); } if (isPresent(this.virtual)) { this.renderer.addClass(this.wrapper.nativeElement, this.listVirtualClass); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, deps: [{ token: i1.DataService }, { token: i0.ElementRef }, { token: i2.SelectionService }, { token: i3.DisabledItemsService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i4.LocalizationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ListComponent, isStandalone: true, selector: "kendo-list", inputs: { selected: "selected", focused: "focused", textField: "textField", valueField: "valueField", height: "height", template: "template", groupTemplate: "groupTemplate", fixedGroupTemplate: "fixedGroupTemplate", show: "show", id: "id", optionPrefix: "optionPrefix", multipleSelection: "multipleSelection", virtual: "virtual", type: "type", checkboxes: "checkboxes", ariaLive: "ariaLive", isMultiselect: "isMultiselect", isActionSheetExpanded: "isActionSheetExpanded", showStickyHeader: "showStickyHeader", rowWidth: "rowWidth", customItemTemplate: "customItemTemplate", text: "text", allowCustom: "allowCustom", defaultItem: "defaultItem", data: "data", size: "size", rounded: "rounded" }, outputs: { onClick: "onClick", pageChange: "pageChange", listResize: "listResize", popupListScroll: "popupListScroll" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }, { propertyName: "list", first: true, predicate: ["list"], descendants: true }, { propertyName: "virtualContainer", first: true, predicate: ["virtualContainer"], descendants: true }, { propertyName: "items", predicate: ListItemDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: ` @if (defaultItem && !template) { <div class="k-list-optionlabel" [ngClass]="{ 'k-disabled': isDisabledDefaultItem }" kendoDropDownsSelectable [index]="-1"> {{ getDefaultItemText() }} </div> } @if (defaultItem && template) { <div class="k-list-optionlabel" [ngClass]="{ 'k-disabled': isDisabledDefaultItem }" kendoDropDownsSelectable [index]="-1"> <ng-template [templateContext]="{ templateRef: template.templateRef, $implicit: defaultItem }"> </ng-template> </div> } @if (allowCustom && text) { <div kendoDropDownsSelectable [multipleSelection]="true" [index]="-1" class="k-list-custom-value"> @if (customItemTemplate) { <ng-template [templateContext]="{ templateRef: customItemTemplate.templateRef, $implicit: text }"> </ng-template> } @else { {{useCustomValueText}} } </div> } @if (dataService.grouped && showStickyHeader) { <div [class]="listGroupStickyHeaderClass" [ngStyle]="{ 'height.px': virtual?.itemHeight, 'minHeight.px' : virtual?.itemHeight, 'boxSizing' : virtual ? 'border-box' : 'inherit'}" > @if (fixedGroupTemplate) { <ng-template [templateContext]="{ templateRef: fixedGroupTemplate.templateRef, $implicit: currentGroup }"> </ng-template> } @if (!fixedGroupTemplate) { <span [class]="listGroupStickyHeaderTextClass">{{ currentGroup }}</span> } </div> } <div #content [class]="listContentClass" [style.maxHeight.px]="height" unselectable="on" (scroll)="popupListScroll.emit($event)" [attr.role]="dataService.grouped ? 'listbox' : null" [attr.id]="dataService.grouped ? id : null" [attr.aria-live]="dataService.grouped ? ariaLive : null" [attr.aria-multiselectable]="dataService.grouped ? isMultiselect : null" [attr.aria-hidden]="dataService.grouped ? !show : null" > @if (!dataService.grouped) { <ul #list [attr.role]="'listbox'" [class]="listClass" [attr.id]="id" [attr.aria-live]="ariaLive" [attr.aria-multiselectable]="isMultiselect" [attr.aria-hidden]="!show"> @for (dataItem of data; track $index; let itemIndex = $index) { <li role="option" kendoDropDownsSelectable [checkboxes]="checkboxes" [height]="virtual?.itemHeight" [index]="itemIndex + startFrom" [multipleSelection]="multipleSelection" [attr.id]="optionPrefix + '-' + itemIndex" [attr.tabIndex]="-1" [attr.aria-selected]="isItemSelected(itemIndex)" [class]="listItemClass" [ngClass]="{ 'k-disabled': isDisabled(itemIndex), 'k-table-alt-row': isAltRow(itemIndex) }" [style.width.px]="rowWidth ?? null" > @if (checkboxes.enabled) { <input type="checkbox" class="k-checkbox" role="presentation" tabindex="-1" [ngClass]="checkboxClasses" (change)="onCheckedChange($event, itemIndex + startFrom)" [checked]="isChecked(itemIndex)" /> } @if (template) { <ng-template [templateContext]="{ templateRef: template.templateRef, $implicit: dataItem }"> </ng-template> } @if (!template) { <span class="k-list-item-text">{{ getText(dataItem) }}</span> } </li> } @if (!virtual) { <kendo-resize-sensor (resize)="listResize.emit()" > </kendo-resize-sensor> } </ul> } @if (dataService.grouped) { <ng-container #list> @for (dataItem of groupedData; track dataItem) { <ul #groupUl class="k-list-ul" [attr.role]="'group'" [attr.aria-labelledby]="generateGroupId(dataItem)" > @if (dataItem.header) { <li role="presentation" [class]="listGroupItemClass" [class.k-table-alt-row]="isAltRow(dataItem.index - 1)" [ngStyle]="{ 'height.px': virtual?.itemHeight, 'minHeight.px' : virtual?.itemHeight, 'boxSizing' : virtual ? 'border-box' : 'inherit'}" [attr.group-index]="dataItem.index" [attr.id]="groupUl.getAttribute('aria-labelledby')" [style.width.px]="rowWidth ?? null" > <span [class]="listGroupItemTextClass"> @if (groupTemplate) { <ng-template [templateContext]="{ templateRef: groupTemplate.templateRef, $implicit: dataItem.value }"> </ng-template> } @if (!groupTemplate) { {{ dataItem.value }} } </span> </li> } @for (item of dataItem.items; track item) { <li role="option" kendoDropDownsSelectable [height]="virtual?.itemHeight" [index]="item.offsetIndex" [multipleSelection]="multipleSelection" [attr.absolute-index]="item.index" [attr.id]="optionPrefix + '-' + (item.index - 1 - item.groupIndex)" [attr.tabIndex]="-1" [attr.aria-selected]="isItemSelected(item.offsetIndex)" [class]="listItemClass" [ngClass]="{ 'k-disabled': isDisabled(item.offsetIndex), 'k-table-alt-row': isAltRow(item.index - 1) }" [style.width.px]="rowWidth ?? null"> @if (template) { <ng-template [templateContext]="{ templateRef: template.templateRef, $implicit: item.value }"> </ng-template> } @if (!template) { <span class="k-list-item-text">{{ getText(item.value) }}</span> } </li> } @if (!virtual) { <kendo-resize-sensor (resize)="listResize.emit()" > </kendo-resize-sensor> } </ul> } </ng-container> } @if (virtual) { <div #virtualContainer class="k-height-container" role="presentation"> <div [style.height.px]="scrollHeight"> <kendo-resize-sensor (resize)="listResize.emit()"></kendo-resize-sensor> </div> </div> } </div> `, isInline: true, dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { kind: "directive", type: ListItemDirective, selector: "\"li[role=option], li[role=group], li[role=presentation]\"" }, { kind: "directive", type: SelectableDirective, selector: "[kendoDropDownsSelectable]", inputs: ["index", "checkboxes", "height", "isMultiselect", "multipleSelection"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, decorators: [{ type: Component, args: [{ selector: 'kendo-list', template: ` @if (defaultItem && !template) { <div class="k-list-optionlabel" [ngClass]="{ 'k-disabled': isDisabledDefaultItem }" kendoDropDownsSelectable [index]="-1"> {{ getDefaultItemText() }} </div> } @if (defaultItem && template) { <div class="k-list-optionlabel" [ngClass]="{ 'k-disabled': isDisabledDefaultItem }" kendoDropDownsSelectable [index]="-1"> <ng-template [templateContext]="{ templateRef: template.templateRef, $implicit: defaultItem }"> </ng-template> </div> } @if (allowCustom && text) { <div kendoDropDownsSelectable [multipleSelection]="true" [index]="-1" class="k-list-custom-value"> @if (customItemTemplate) { <ng-template [templateContext]="{ templateRef: customItemTemplate.templateRef, $implicit: text }"> </ng-template> } @else { {{useCustomValueText}} } </div> } @if (dataService.grouped && showStickyHeader) { <div [class]="listGroupStickyHeaderClass" [ngStyle]="{ 'height.px': virtual?.itemHeight, 'minHeight.px' : virtual?.itemHeight, 'boxSizing' : virtual ? 'border-box' : 'inherit'}" > @if (fixedGroupTemplate) { <ng-template [templateContext]="{ templateRef: fixedGroupTemplate.templateRef, $implicit: currentGroup }"> </ng-template> } @if (!fixedGroupTemplate) { <span [class]="listGroupStickyHeaderTextClass">{{ currentGroup }}</span> } </div> } <div #content [class]="listContentClass" [style.maxHeight.px]="height" unselectable="on" (scroll)="popupListScroll.emit($event)" [attr.role]="dataService.grouped ? 'listbox' : null" [attr.id]="dataService.grouped ? id : null" [attr.aria-live]="dataService.grouped ? ariaLive : null" [attr.aria-multiselectable]="dataService.grouped ? isMultiselect : null" [attr.aria-hidden]="dataService.grouped ? !show : null" > @if (!dataService.grouped) { <ul #list [attr.role]="'listbox'" [class]="listClass" [attr.id]="id" [attr.aria-live]="ariaLive" [attr.aria-multiselectable]="isMultiselect" [attr.aria-hidden]="!show"> @for (dataItem of data; track $index; let itemIndex = $index) { <li role="option" kendoDropDownsSelectable [checkboxes]="checkboxes" [height]="virtual?.itemHeight" [index]="itemIndex + startFrom" [multipleSelection]="multipleSelection" [attr.id]="optionPrefix + '-' + itemIndex" [attr.tabIndex]="-1" [attr.aria-selected]="isItemSelected(itemIndex)" [class]="listItemClass" [ngClass]="{ 'k-disabled': isDisabled(itemIndex), 'k-table-alt-row': isAltRow(itemIndex) }" [style.width.px]="rowWidth ?? null" > @if (checkboxes.enabled) { <input type="checkbox" class="k-checkbox" role="presentation" tabindex="-1" [ngClass]="checkboxClasses" (change)="onCheckedChange($event, itemIndex + startFrom)" [checked]="isChecked(itemIndex)" /> } @if (template) { <ng-template [templateContext]="{ templateRef: template.templateRef, $implicit: dataItem }"> </ng-template> } @if (!template) { <span class="k-list-item-text">{{ getText(dataItem) }}</span> } </li> } @if (!virtual) { <kendo-resize-sensor (resize)="listResize.emit()" > </kendo-resize-sensor> } </ul> } @if (dataService.grouped) { <ng-container #list> @for (dataItem of groupedData; track dataItem) { <ul #groupUl class="k-list-ul" [attr.role]="'group'" [attr.aria-labelledby]="generateGroupId(dataItem)" > @if (dataItem.header) { <li role="presentation" [class]="listGroupItemClass" [class.k-table-alt-row]="isAltRow(dataItem.index - 1)" [ngStyle]="{ 'height.px': virtual?.itemHeight, 'minHeight.px' : virtual?.itemHeight, 'boxSizing' : virtual ? 'border-box' : 'inherit'}" [attr.group-index]="dataItem.index" [attr.id]="groupUl.getAttribute('aria-labelledby')" [style.width.px]="rowWidth ?? null" > <span [class]="listGroupItemTextClass"> @if (groupTemplate) { <ng-template [templateContext]="{ templateRef: groupTemplate.templateRef, $implicit: dataItem.value }"> </ng-template> } @if (!groupTemplate) { {{ dataItem.value }} } </span> </li> } @for (item of dataItem.items; track item) { <li role="option" kendoDropDownsSelectable [height]="virtual?.itemHeight" [index]="item.offsetIndex" [multipleSelection]="multipleSelection" [attr.absolute-index]="item.index" [attr.id]="optionPrefix + '-' + (item.index - 1 - item.groupIndex)" [attr.tabIndex]="-1" [attr.aria-selected]="isItemSelected(item.offsetIndex)" [class]="listItemClass" [ngClass]="{ 'k-disabled': isDisabled(item.offsetIndex), 'k-table-alt-row': isAltRow(item.index - 1) }" [style.width.px]="rowWidth ?? null"> @if (template) { <ng-template [templateContext]="{ templateRef: template.templateRef, $implicit: item.value }"> </ng-template> } @if (!template) { <span class="k-list-item-text">{{ getText(item.value) }}</span> } </li> } @if (!virtual) { <kendo-resize-sensor (resize)="listResize.emit()" > </kendo-resize-sensor> } </ul> } </ng-container> } @if (virtual) { <div #virtualContainer class="k-height-container" role="presentation"> <div [style.height.px]="scrollHeight"> <kendo-resize-sensor (resize)="listResize.emit()"></kendo-resize-sensor> </div> </div> } </div> `, standalone: true, imports: [NgStyle, TemplateContextDirective, ListItemDirective, SelectableDirective, NgClass, ResizeSensorComponent] }] }], ctorParameters: () => [{ type: i1.DataService }, { type: i0.ElementRef }, { type: i2.SelectionService }, { type: i3.DisabledItemsService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i4.LocalizationService }], propDecorators: { selected: [{ type: Input }], focused: [{ type: Input }], textField: [{ type: Input }], valueField: [{ type: Input }], height: [{ type: Input }], template: [{ type: Input }], groupTemplate: [{ type: Input }], fixedGroupTemplate: [{ type: Input }], show: [{ type: Input }], id: [{ type: Input }], optionPrefix: [{ type: Input }], multipleSelection: [{ type: Input }], virtual: [{ type: Input }], type: [{ type: Input }], checkboxes: [{ type: Input }], ariaLive: [{ type: Input }], isMultiselect: [{ type: Input }], isActionSheetExpanded: [{ type: Input }], showStickyHeader: [{ type: Input }], rowWidth: [{ type: Input }], customItemTemplate: [{ type: Input }], text: [{ type: Input }], allowCustom: [{ type: Input }], defaultItem: [{ type: Input }], data: [{ type: Input }], size: [{ type: Input }], rounded: [{ type: Input }], onClick: [{ type: Output }], pageChange: [{ type: Output }], listResize: [{ type: Output }], popupListScroll: [{ type: Output }], items: [{ type: ViewChildren, args: [ListItemDirective] }], content: [{ type: ViewChild, args: ['content', { static: true }] }], list: [{ type: ViewChild, args: ['list'] }], virtualContainer: [{ type: ViewChild, args: ['virtualContainer'] }] } });