@progress/kendo-angular-treelist
Version:
Kendo UI TreeList for Angular - Display hierarchical data in an Angular tree grid view that supports sorting, filtering, paging, and much more.
1,264 lines (1,249 loc) • 1.04 MB
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 { Directive, Optional, EventEmitter, Injectable, QueryList, Input, ContentChildren, ContentChild, InjectionToken, forwardRef, Component, SkipSelf, Host, isDevMode, SecurityContext, Inject, Output, HostBinding, Pipe, ViewChild, ViewChildren, Self, HostListener, NgZone, TemplateRef, ChangeDetectionStrategy, ViewEncapsulation, NgModule } from '@angular/core';
import * as i1$4 from '@progress/kendo-angular-common';
import { isDocumentAvailable, isPresent as isPresent$1, hasClasses as hasClasses$1, Keys, normalizeNumpadKeys, anyChanged, isChanged as isChanged$1, ResizeSensorComponent, EventsOutsideAngularDirective, KendoInput, replaceMessagePlaceholder, guid, DraggableDirective, TemplateContextDirective, hasObservers, ResizeBatchService } from '@progress/kendo-angular-common';
import * as i2 from '@progress/kendo-angular-icons';
import { IconWrapperComponent, IconsService, KENDO_ICONS } from '@progress/kendo-angular-icons';
import { DatePickerComponent, DatePickerCustomMessagesComponent, CalendarDOMService, CenturyViewService, DecadeViewService, MonthViewService, YearViewService, NavigationService as NavigationService$1 } from '@progress/kendo-angular-dateinputs';
import * as i1 from '@progress/kendo-angular-popup';
import { PopupService } from '@progress/kendo-angular-popup';
import { DialogContainerService, DialogService, WindowService, WindowContainerService } from '@progress/kendo-angular-dialog';
import { NgSwitch, NgSwitchCase, NgIf, NgFor, NgTemplateOutlet, NgSwitchDefault, NgClass, NgStyle } from '@angular/common';
import * as i4 from '@angular/forms';
import { ReactiveFormsModule, NG_VALUE_ACCESSOR, FormsModule, FormControl, FormGroup } from '@angular/forms';
import { merge, of, fromEvent, isObservable, BehaviorSubject, Subscription, Subject, zip as zip$1, from, interval, Observable } from 'rxjs';
import { auditTime, take, switchMap, map, distinctUntilChanged, filter, tap, throttleTime, skip, takeUntil, switchMapTo, bufferCount, delay, debounceTime } from 'rxjs/operators';
import { validatePackage } from '@progress/kendo-licensing';
import * as i1$1 from '@progress/kendo-angular-l10n';
import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
import { DragTargetContainerDirective, DropTargetContainerDirective } from '@progress/kendo-angular-utils';
import { orderBy, isCompositeFilterDescriptor, process, aggregateBy } from '@progress/kendo-data-query';
import * as i1$2 from '@angular/platform-browser';
import { plusIcon, cancelIcon, lockIcon, unlockIcon, insertMiddleIcon, caretAltDownIcon, caretAltRightIcon, caretAltLeftIcon, reorderIcon, filterClearIcon, filterIcon, chevronUpIcon, chevronDownIcon, columnsIcon, sortAscSmallIcon, sortDescSmallIcon, displayInlineFlexIcon, maxWidthIcon, moreVerticalIcon, fileExcelIcon, filePdfIcon } from '@progress/kendo-svg-icons';
import * as i107 from '@progress/kendo-angular-pager';
import { PagerContextService, PagerNavigationService, PagerTemplateDirective, KENDO_PAGER } from '@progress/kendo-angular-pager';
import { getter, setter } from '@progress/kendo-common';
import * as i1$6 from '@progress/kendo-angular-inputs';
import { NumericTextBoxComponent, CheckBoxComponent, TextBoxComponent, NumericTextBoxCustomMessagesComponent, RadioButtonComponent } from '@progress/kendo-angular-inputs';
import * as i1$3 from '@progress/kendo-angular-intl';
import * as i1$5 from '@progress/kendo-angular-dropdowns';
import { DropDownListComponent, AutoCompleteComponent } from '@progress/kendo-angular-dropdowns';
import { ButtonComponent, Button } from '@progress/kendo-angular-buttons';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { saveAs } from '@progress/kendo-file-saver';
import * as i100 from '@progress/kendo-angular-excel-export';
import { workbookOptions, toDataURL, ColumnBase as ColumnBase$1, ColumnComponent as ColumnComponent$1, ColumnGroupComponent as ColumnGroupComponent$1, FooterTemplateDirective as FooterTemplateDirective$1, GroupFooterTemplateDirective, GroupHeaderColumnTemplateDirective, GroupHeaderTemplateDirective } from '@progress/kendo-angular-excel-export';
import * as i106 from '@progress/kendo-angular-toolbar';
import { KENDO_TOOLBAR } from '@progress/kendo-angular-toolbar';
import { PDFExportMarginComponent, PDFExportTemplateDirective, PDFExportComponent } from '@progress/kendo-angular-pdf-export';
/**
* @hidden
*/
const packageMetadata = {
name: '@progress/kendo-angular-treelist',
productName: 'Kendo UI for Angular',
productCode: 'KENDOUIANGULAR',
productCodes: ['KENDOUIANGULAR'],
publishDate: 1756992973,
version: '20.0.3',
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
};
/**
* Represents the column cell template of the TreeList ([more information and example]({% slug templates_columns_treelist %}#toc-cell-template)).
* Use this directive to customize the content of the cells. To define the cell template, nest an `<ng-template>` tag with the `kendoTreeListCellTemplate` directive inside a `<kendo-treelist-column>` tag.
*
* The template context is set to the current data item and provides the following fields:
* - `columnIndex`—The current column index. Use as an alias for a template variable with `let-columnIndex="columnIndex"`.
* - `column`—The current column instance. Use as an alias for a template variable with `let-column="column"`.
* - `dataItem`—The current data item. Represents the default context for any template variable using `let-x` syntax, for example, `let-dataItem`.
* - `cellContext`—An object for passing context information to built-in directives.
* - `hasChildren`—Specifies if the item has children.
* - `isExpanded`—Specifies if the item is expanded.
* - `level`—The hierarchy level of the item.
* - `loading`—Specifies if the item children are currently loading.
* - `rowIndex`—The current row index. Use it as an alias for a template variable with `let-rowIndex="rowIndex"`.
*
* @example
* ```html
* <kendo-treelist ...>
* <kendo-treelist-column field="ProductName">
* <ng-template kendoTreeListCellTemplate let-dataItem let-rowIndex="rowIndex" let-column="column">
* Data Row: {{rowIndex}}
* </ng-template>
* </kendo-treelist-column>
* </kendo-treelist>
* ```
*/
class CellTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: CellTemplateDirective, isStandalone: true, selector: "[kendoTreeListCellTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoTreeListCellTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* Represents the column edit-cell template of the TreeList ([see example](slug:editing_template_forms_treelist)). Use this directive to customize the content of edited cells. To define the cell template, nest an `<ng-template>` tag with the `kendoTreeListEditTemplate` directive inside a `<kendo-treelist-column>` tag.
*
* The template context contains the following fields:
* - `column`—The current column instance.
* - `dataItem`—The current data item.
* - `cellContext`—An object used to pass context information to built-in directives.
* - `formGroup`—The current [`FormGroup`](link:site.data.urls.angular['formgroupapi']). If you use the TreeList inside [Template-Driven Forms](link:site.data.urls.angular['forms']), `formGroup` is `undefined`.
* - `isNew`—The state of the current item.
* - `rowIndex`—The current row index. If inside a new item row, `rowIndex` is `-1`.
*
* @example
* ```html
* <kendo-treelist ...>
* <kendo-treelist-command-column title="command">
* <ng-template kendoTreeListEditTemplate let-rowIndex="rowIndex">
* {{rowIndex}}
* </ng-template>
* </kendo-treelist-command-column>
* </kendo-treelist>
* ```
*/
class EditTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EditTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: EditTemplateDirective, isStandalone: true, selector: "[kendoTreeListEditTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EditTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoTreeListEditTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* Represents the template for the column menu in the TreeList. Use this directive to customize the content of the column menu for all or specific columns.
* To define the content template, nest an `<ng-template>` tag with the `kendoTreeListColumnMenuTemplate` directive inside the `kendo-treelist` or the `<kendo-treelist-column>` component.
*
* The template context is passed through the following fields:
* - `service`—Represents the [ColumnMenuService]({% slug api_treelist_columnmenuservice %}).
* - `column`—Represents the TreeList column.
*
* @example
* ```html
* <kendo-treelist ... >
* <ng-template kendoTreeListColumnMenuTemplate let-service="service">
* <kendo-treelist-columnmenu-sort [service]="service">
* </kendo-treelist-columnmenu-sort>
* </ng-template>
* <kendo-treelist-column field="name">
* <ng-template kendoTreeListColumnMenuTemplate let-service="service">
* <kendo-treelist-columnmenu-sort [service]="service">
* </kendo-treelist-columnmenu-sort>
* </ng-template>
* </kendo-treelist-column>
* </kendo-treelist>
* ```
*/
class ColumnMenuTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ColumnMenuTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ColumnMenuTemplateDirective, isStandalone: true, selector: "[kendoTreeListColumnMenuTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ColumnMenuTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoTreeListColumnMenuTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* @hidden
*/
class OptionChangesService {
columns = new EventEmitter();
options = new EventEmitter();
optionChanged() {
this.options.emit();
}
columnChanged() {
this.columns.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OptionChangesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OptionChangesService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OptionChangesService, decorators: [{
type: Injectable
}] });
/**
* Represents the column footer cell template of the TreeList ([more information and example]({% slug templates_columns_treelist %}#toc-footer-template)).
* Use this directive to customize the table footer cell for the column.
* To define a footer template, nest an `<ng-template>` tag with the `kendoTreeListFooterTemplate` directive inside the `<kendo-treelist-column>` tag.
*
* The template context is set to the aggregate values and provides the following fields:
* - `aggregates`—The aggregates for the level items.
* - `column`—Defines an instance of the [`ColumnComponent`]({% slug api_treelist_columncomponent %}) option.
* - `columnIndex`—Defines the current column index.
* - `field`—The name of the column field, if set.
* - `items`—The data items on this level.
* - `parentItem`—The parent data item; `null` for root level items.
*
* @example
* ```html
* <kendo-treelist-column field="name">
* <ng-template kendoTreeListFooterTemplate let-aggregates="aggregates">
* {{ aggregates.name.count }}
* </ng-template>
* </kendo-treelist-column>
* ```
*/
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, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FooterTemplateDirective, isStandalone: true, selector: "[kendoTreeListFooterTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FooterTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoTreeListFooterTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* Represents the column header cell template of the TreeList
* ([more information and example]({% slug templates_columns_treelist %}#toc-header-template)).
* Use this directive to customize the table header cell for the column.
* To define a header template, nest an `<ng-template>` tag with the
* [`kendoTreeListHeaderTemplate`]({% slug api_treelist_headertemplatedirective %}) directive inside the `<kendo-treelist-column>` tag.
*
* The template context is set to the current column and provides the following fields:
* - `column`—Defines an instance of the [`ColumnComponent`]({% slug api_treelist_columncomponent %}) option.
* - `columnIndex`—Defines the current column index.
*
* @example
* ```html
* <kendo-treelist-column field="name">
* <ng-template
* kendoTreeListHeaderTemplate
* let-column>
* {{ column.field }}
* </ng-template>
* </kendo-treelist-column>
* ```
*/
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, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HeaderTemplateDirective, isStandalone: true, selector: "[kendoTreeListHeaderTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeaderTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoTreeListHeaderTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
let columnId = 0;
/**
* @hidden
*/
const isSpanColumn = column => column.isSpanColumn;
/**
* @hidden
*/
const isCheckboxColumn = column => column.isCheckboxColumn;
/**
* @hidden
*/
const isRowReorderColumn = column => column.isRowReorderColumn;
const isColumnContainer = column => column.isColumnGroup || isSpanColumn(column);
/**
* Serves as the base class for column components in the TreeList.
*/
class ColumnBase {
parent;
optionChanges;
/**
* @hidden
*/
matchesMedia = true;
/**
* The column index after reordering.
* The orderIndex` is a read-only property. Setting this field does not affect column order.
* @default 0
*/
orderIndex = 0;
/**
* @hidden
*/
set leafIndex(value) {
this._leafIndex = value;
}
/**
* @hidden
*/
get leafIndex() {
return this._leafIndex;
}
_leafIndex;
/**
* @hidden
*/
isColumnGroup = false;
/**
* @hidden
*/
isSpanColumn = false;
/**
* @hidden
*/
get id() {
return this._id;
}
/**
* Indicates whether the column is resizable.
* @default true
*/
resizable = true;
/**
* Indicates whether the column is reorderable.
* @default true
*/
reorderable = true;
/**
* Sets the minimum width (in pixels) for resizing the column using the UI.
* @default 10
*/
minResizableWidth = 10;
/**
* Sets the title of the column.
*/
title;
/**
* Sets the width of the column (in pixels).
*/
set width(value) {
this._width = parseInt(value, 10);
}
get width() { return this._width; }
/**
* Indicates whether the column is automatically resized during initialization to fit its header and row content.
*/
autoSize;
/**
* Toggles the locked (frozen) state of the columns ([more information and example](slug:locked_columns_treelist)).
* @default false
*/
set locked(value) {
this._locked = value;
}
get locked() {
return this._locked;
}
_locked = false;
/**
* Sets the visibility of the column ([see example](slug:hidden_columns_treelist#toc-using-the-built-in-options)).
* @default false
*/
hidden;
/**
* Sets the condition that must be satisfied for a column to remain visible ([see example](slug:responsive_treelist#toc-columns)).
* If you set the `hidden` property, the behavior of `media` is overridden.
*/
media;
/**
* Specifies if the column can be locked or unlocked from the column menu or by reordering the columns.
* @default true
*/
lockable = true;
/**
* Specifies if the column menu is shown for the column.
* @default true
*/
columnMenu = true;
/**
* Specifies if the column is included in the column-chooser list.
* @default true
*/
includeInChooser = true;
/**
* Sets the `role` attribute for the table cells (excluding the footer and header) of the column.
* @default "gridcell"
*/
tableCellsRole = 'gridcell';
/**
* Sets custom styles for the table cells (excluding the footer and header) of the column. Uses the [`NgStyle`](link:site.data.urls.angular['ngstyleapi']) directive. [See example](slug:styling_treelist_columns).
*/
style;
/**
* Sets custom styles for the header cell of the column. Uses the [`NgStyle`](link:site.data.urls.angular['ngstyleapi']) directive. [See example.](slug:styling_treelist_columns)
*/
headerStyle;
/**
* Sets custom styles for the footer cell of the column. Uses the [`NgStyle`](link:site.data.urls.angular['ngstyleapi']) directive. [See example.](slug:styling_treelist_columns)
*/
footerStyle;
/**
* Sets custom CSS classes to the column cells. Uses the [`NgClass`](link:site.data.urls.angular['ngclassapi']) directive. To customize header and footer column cells, use the [`headerClass`]({% slug api_treelist_columncomponent %}#toc-headerclass) and [`footerClass`]({% slug api_treelist_columncomponent %}#toc-footerclass) inputs.
*/
cssClass;
/**
* Sets custom CSS classes to the column header cell. Uses the [`NgClass`](link:site.data.urls.angular['ngclassapi']) directive. [See example](slug:styling_treelist_columns).
*/
headerClass;
/**
* Sets the custom CSS classes to the column footer cell. Under the hood, to apply the property,
* the `footerClass` option uses the
* [`NgClass`](link:site.data.urls.angular['ngclassapi']) directive. [See example](slug:styling_treelist_columns).
*/
footerClass;
/**
* @hidden
*/
headerTemplates = new QueryList();
/**
* @hidden
*/
footerTemplate;
/**
* @hidden
*/
columnMenuTemplates = new QueryList();
/**
* @hidden
*/
resizeStartWidth;
/**
* @hidden
*/
get level() {
if (this.parent && isSpanColumn(this.parent)) {
return this.parent.level;
}
return this.parent ? this.parent.level + 1 : 0;
}
/**
* @hidden
*/
get isLocked() {
return this.parent ? this.parent.isLocked : this.locked;
}
_width;
/**
* @hidden
*/
get colspan() {
return 1;
}
/**
* @hidden
*/
rowspan(totalColumnLevels) {
return this.level < totalColumnLevels ? (totalColumnLevels - this.level) + 1 : 1;
}
/**
* @hidden
*/
get headerTemplateRef() {
const template = this.headerTemplates.first;
return template ? template.templateRef : undefined;
}
/**
* @hidden
*/
get footerTemplateRef() {
return this.footerTemplate ? this.footerTemplate.templateRef : undefined;
}
/**
* @hidden
*/
get columnMenuTemplateRef() {
const template = this.columnMenuTemplates.first;
return template ? template.templateRef : null;
}
/**
* @hidden
*/
get displayTitle() {
return this.title;
}
/**
* @hidden
*/
get isVisible() {
return !this.hidden && this.matchesMedia;
}
/**
* @hidden
*/
get isEditable() {
return false;
}
_id;
/**
* @hidden
*/
constructor(parent, optionChanges) {
this.parent = parent;
this.optionChanges = optionChanges;
if (parent && !isColumnContainer(parent)) {
throw new Error('Columns can be nested only inside ColumnGroupComponent');
}
this._id = `k-grid-column-${columnId++}`;
}
ngOnChanges(_changes) {
if (this.optionChanges) {
this.optionChanges.columnChanged();
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ColumnBase, deps: [{ token: ColumnBase }, { token: OptionChangesService }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ColumnBase, inputs: { resizable: "resizable", reorderable: "reorderable", minResizableWidth: "minResizableWidth", title: "title", width: "width", autoSize: "autoSize", locked: "locked", hidden: "hidden", media: "media", lockable: "lockable", columnMenu: "columnMenu", includeInChooser: "includeInChooser", tableCellsRole: "tableCellsRole", style: "style", headerStyle: "headerStyle", footerStyle: "footerStyle", cssClass: ["class", "cssClass"], headerClass: "headerClass", footerClass: "footerClass" }, queries: [{ propertyName: "footerTemplate", first: true, predicate: FooterTemplateDirective, descendants: true }, { propertyName: "headerTemplates", predicate: HeaderTemplateDirective }, { propertyName: "columnMenuTemplates", predicate: ColumnMenuTemplateDirective }], usesOnChanges: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ColumnBase, decorators: [{
type: Directive,
args: [{}]
}], ctorParameters: function () { return [{ type: ColumnBase }, { type: OptionChangesService }]; }, propDecorators: { resizable: [{
type: Input
}], reorderable: [{
type: Input
}], minResizableWidth: [{
type: Input
}], title: [{
type: Input
}], width: [{
type: Input
}], autoSize: [{
type: Input
}], locked: [{
type: Input
}], hidden: [{
type: Input
}], media: [{
type: Input
}], lockable: [{
type: Input
}], columnMenu: [{
type: Input
}], includeInChooser: [{
type: Input
}], tableCellsRole: [{
type: Input
}], style: [{
type: Input
}], headerStyle: [{
type: Input
}], footerStyle: [{
type: Input
}], cssClass: [{
type: Input,
args: ['class']
}], headerClass: [{
type: Input
}], footerClass: [{
type: Input
}], headerTemplates: [{
type: ContentChildren,
args: [HeaderTemplateDirective, { descendants: false }]
}], footerTemplate: [{
type: ContentChild,
args: [FooterTemplateDirective, { static: false }]
}], columnMenuTemplates: [{
type: ContentChildren,
args: [ColumnMenuTemplateDirective]
}] } });
const EMPTY_REGEX = /^\s*$/;
/**
* @hidden
*/
const isPresent = (value) => value !== null && value !== undefined;
/**
* @hidden
*/
const isBlank = (value) => value === null || value === undefined;
/**
* @hidden
*/
const isArray = (value) => Array.isArray(value);
/**
* @hidden
*/
const isTruthy = (value) => !!value;
/**
* @hidden
*/
const isNullOrEmptyString = (value) => isBlank(value) || EMPTY_REGEX.test(value);
/**
* @hidden
*/
const observe = (list) => merge(of(list), list.changes);
/**
* @hidden
*/
const isUniversal = () => typeof document === 'undefined';
/**
* @hidden
*/
const isString = (value) => typeof value === 'string';
/**
* @hidden
*/
const isNumber = (value) => typeof value === "number" && !isNaN(value);
/**
* @hidden
*/
const extractFormat = (format) => {
if (isString(format) && !isNullOrEmptyString(format) && format.startsWith('{0:')) {
return format.slice(3, format.length - 1);
}
return format;
};
/**
* @hidden
*/
const not = (fn) => (...args) => !fn(...args);
/**
* @hidden
*/
const or = (...conditions) => (value) => conditions.reduce((acc, x) => acc || x(value), false);
/**
* @hidden
*/
const and = (...conditions) => (value) => conditions.reduce((acc, x) => acc && x(value), true);
/**
* @hidden
*/
const Skip = new InjectionToken("Skip");
/**
* @hidden
*/
const createPromise = () => {
let resolveFn, rejectFn;
const promise = new Promise((resolve, reject) => {
resolveFn = (data) => {
resolve(data);
return promise;
};
rejectFn = (data) => {
reject(data);
return promise;
};
});
promise.resolve = resolveFn;
promise.reject = rejectFn;
return promise;
};
/** @hidden */
const iterator = getIterator();
// TODO: Move to kendo-common
function getIterator() {
if (typeof Symbol === 'function' && Symbol.iterator) {
return Symbol.iterator;
}
const keys = Object.getOwnPropertyNames(Map.prototype);
const proto = Map.prototype;
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
if (key !== 'entries' && key !== 'size' && proto[key] === proto.entries) {
return key;
}
}
}
const FRAME_DURATION = 1000 / 60;
const wnd = typeof window !== 'undefined' ? window : {};
/** @hidden */
const requestAnimationFrame = wnd.requestAnimationFrame || wnd.msRequestAnimationFrame || (callback => setTimeout(callback, FRAME_DURATION));
/** @hidden */
const cancelAnimationFrame = wnd.cancelAnimationFrame || wnd.msCancelRequestAnimationFrame || clearTimeout;
/** @hidden */
const isColumnEditable = (column, formGroup) => column.isEditable !== false &&
(column.editTemplate || (formGroup && column.field && formGroup.get(column.field)));
/**
* Represents the filter-cell template for the TreeList.
* Use this directive to customize the filter row cell for a column.
* See [custom filter row components](slug:filter_row_treelist#toc-custom-filters).
*
* The template context is set to the filter descriptor and provides the following fields:
* - `column`—The current column instance. Use as an alias for a template variable with `let-column="column"`.
* - `filter`—The filter descriptor.
* - `cellContext`—An object used to pass context information to built-in directives.
*
* @example
* ```html
* <kendo-treelist-column field="name" title="Name">
* <ng-template kendoTreeListFilterCellTemplate let-column="column" let-filter="filter" let-cellContext="cellContext">
* <kendo-maskedtextbox mask="(999) 000-0000"
* [promptPlaceholder]="prompt" [includeLiterals]="true"
* (valueChange)="phoneChange($event)"
* >
* </kendo-maskedtextbox>
* </ng-template>
* </kendo-treelist-column>
* ```
*/
class FilterCellTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FilterCellTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FilterCellTemplateDirective, isStandalone: true, selector: "[kendoTreeListFilterCellTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FilterCellTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoTreeListFilterCellTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* Represents the filter-menu template for the TreeList filter menu.
*
* Use this directive to provide a custom template for the filter menu in a TreeList column
* ([see example](slug:filter_menu_treelist#toc-custom-filter-menu-components)).
*
* @example
* ```html
* <kendo-treelist-column field="title" title="Title" [width]="180">
* <ng-template kendoTreeListFilterMenuTemplate
* let-filter="filter"
* let-filterService="filterService">
* <my-custom-filter-menu-component
* [currentFilter]="filter"
* [filterService]="filterService">
* </my-custom-filter-menu-component>
* </ng-template>
* </kendo-treelist-column>
* ```
*/
class FilterMenuTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FilterMenuTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FilterMenuTemplateDirective, isStandalone: true, selector: "[kendoTreeListFilterMenuTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FilterMenuTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoTreeListFilterMenuTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* @hidden
*/
function isColumnComponent(column) {
return isPresent(column.field);
}
/**
* Represents a column in the TreeList. Use this component to define a data-bound column.
*
* @example
* ```html
* <kendo-treelist [kendoTreeListFlatBinding]="data" ...>
* <kendo-treelist-column field="name" title="Name"></kendo-treelist-column>
* <kendo-treelist-column field="title" title="Title"></kendo-treelist-column>
* </kendo-treelist>
* ```
* @remarks
* Supported children components are:
* {@link StringFilterCellComponent},
* {@link NumericFilterCellComponent},
* {@link BooleanFilterCellComponent},
* {@link DateFilterCellComponent},
* {@link StringFilterMenuComponent},
* {@link NumericFilterMenuComponent},
* {@link BooleanFilterMenuComponent},
* {@link DateFilterMenuComponent},
* {@link FilterCellOperatorsComponent}.
*/
class ColumnComponent extends ColumnBase {
/**
* Specifies if the expanded indicator appears in the column.
*/
expandable;
/**
* Sets the field to which the column is bound.
*/
field;
/**
* Sets the format applied to the value before display. For supported date and number formats, see the [Column Formats](slug:formats_columns_treelist) article.
*/
format;
/**
* Allows the column headers to be clicked and the `sortChange` event emitted. You must handle the `sortChange` event and sort the data.
* @default true
*/
sortable = true;
/**
* Sets the editor type ([see example]({% slug editing_reactive_forms_treelist %}#toc-setup)). Used when the column enters edit mode. [See example](slug:editing_reactive_forms_treelist).
* @default 'text'
*/
editor = 'text';
/**
* Sets the filter type displayed inside the filter row.
* @default 'text'
*/
filter = 'text';
/**
* Specifies if a filter UI appears for this column.
* @default true
*/
filterable = true;
/**
* Specifies if the column is editable.
* @default true
*/
editable = true;
template;
editTemplate;
filterCellTemplate;
filterMenuTemplate;
constructor(parent, optionChanges) {
super(parent, optionChanges);
}
get templateRef() {
return this.template ? this.template.templateRef : undefined;
}
get editTemplateRef() {
return this.editTemplate ? this.editTemplate.templateRef : undefined;
}
get filterCellTemplateRef() {
return this.filterCellTemplate ? this.filterCellTemplate.templateRef : undefined;
}
get filterMenuTemplateRef() {
return this.filterMenuTemplate ? this.filterMenuTemplate.templateRef : undefined;
}
get displayTitle() {
return this.title === undefined ? this.field : this.title;
}
/**
* @hidden
*/
get isEditable() {
return this.editable !== false;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ColumnComponent, deps: [{ token: ColumnBase, host: true, optional: true, skipSelf: true }, { token: OptionChangesService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ColumnComponent, isStandalone: true, selector: "kendo-treelist-column", inputs: { expandable: "expandable", field: "field", format: "format", sortable: "sortable", editor: "editor", filter: "filter", filterable: "filterable", editable: "editable" }, providers: [
{
provide: ColumnBase,
useExisting: forwardRef(() => ColumnComponent)
}
], queries: [{ propertyName: "template", first: true, predicate: CellTemplateDirective, descendants: true }, { propertyName: "editTemplate", first: true, predicate: EditTemplateDirective, descendants: true }, { propertyName: "filterCellTemplate", first: true, predicate: FilterCellTemplateDirective, descendants: true }, { propertyName: "filterMenuTemplate", first: true, predicate: FilterMenuTemplateDirective, descendants: true }], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ColumnComponent, decorators: [{
type: Component,
args: [{
providers: [
{
provide: ColumnBase,
useExisting: forwardRef(() => ColumnComponent)
}
],
selector: 'kendo-treelist-column',
template: ``,
standalone: true
}]
}], ctorParameters: function () { return [{ type: ColumnBase, decorators: [{
type: SkipSelf
}, {
type: Host
}, {
type: Optional
}] }, { type: OptionChangesService }]; }, propDecorators: { expandable: [{
type: Input
}], field: [{
type: Input
}], format: [{
type: Input
}], sortable: [{
type: Input
}], editor: [{
type: Input
}], filter: [{
type: Input
}], filterable: [{
type: Input
}], editable: [{
type: Input
}], template: [{
type: ContentChild,
args: [CellTemplateDirective, { static: false }]
}], editTemplate: [{
type: ContentChild,
args: [EditTemplateDirective, { static: false }]
}], filterCellTemplate: [{
type: ContentChild,
args: [FilterCellTemplateDirective, { static: false }]
}], filterMenuTemplate: [{
type: ContentChild,
args: [FilterMenuTemplateDirective, { static: false }]
}] } });
/**
* @hidden
*/
function isSpanColumnComponent(column) {
return column.isSpanColumn;
}
/**
* Represents a column that spans multiple data cells while keeping individual header and footer cells.
* Use this component to create flexible layouts and retain built-in UI for [sorting]({% slug sorting_treelist %}) and [filtering]({% slug filtering_treelist %}).
* Wrap the columns to merge inside the `<kendo-treelist-span-column>` tag.
*
* @example
* ```html
* <kendo-treelist-span-column>
* <kendo-treelist-column field="field1"></kendo-treelist-column>
* <kendo-treelist-column field="field2"></kendo-treelist-column>
* <ng-template kendoTreeListCellTemplate let-dataItem>
* <h5>{{ dataItem.field1 }}</h5>
* <p>{{ dataItem.field2 }}</p>
* </ng-template>
* </kendo-treelist-span-column>
* ```
*/
class SpanColumnComponent extends ColumnBase {
/**
* Specifies if the expanded indicator appears in the column.
*/
expandable;
/*
* @hidden
*/
isSpanColumn = true;
/**
* @hidden
*/
title;
/**
* @hidden
*/
headerClass;
/**
* @hidden
*/
footerClass;
/**
* @hidden
*/
headerStyle;
/**
* @hidden
*/
footerStyle;
template = new QueryList();
editTemplate = new QueryList();
/**
* @hidden
*/
childColumns = new QueryList();
/**
* @hidden
*/
includeInChooser = false;
/**
* Defines whether the edit template of the column is rendered.
* To enable editing for a spanned column, set an edit template for it.
* @default false
*/
set editable(value) {
this._editable = value;
}
get editable() {
return isPresent(this.editTemplateRef) && this._editable;
}
/**
* @hidden
* added for backwards compitability
*/
set width(_value) {
}
get width() {
return this.childColumns.reduce((total, column) => total + column.width, 0);
}
/**
* @hidden
*/
get leafIndex() {
return this.childColumns.first.leafIndex;
}
_editable = true;
constructor(parent, optionChanges) {
super(parent, optionChanges);
if (parent && parent.isSpanColumn) {
throw new Error('SpanColumn cannot be nested inside another SpanColumn');
}
}
/**
* @hidden
*/
get templateRef() {
const template = this.template.first;
return template ? template.templateRef : undefined;
}
/**
* @hidden
*/
get editTemplateRef() {
const editTemplate = this.editTemplate.first;
return editTemplate ? editTemplate.templateRef : undefined;
}
/**
* @hidden
*/
get colspan() {
return this.childColumns.filter(c => c.isVisible).length;
}
/**
* Toggles the locked (frozen) state of the columns. Locked columns are visible at all times during horizontal scrolling. [See example](slug:locked_columns_treelist).
* @default false
*/
set locked(value) {
this._locked = value;
}
get locked() {
return this._locked || this.childColumns.some(c => c.locked);
}
get isEditable() {
return Boolean(this.editTemplateRef);
}
get childrenArray() {
return this.childColumns.toArray();
}
get hasChildren() {
return this.childColumns.length > 0;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpanColumnComponent, deps: [{ token: ColumnBase, host: true, optional: true, skipSelf: true }, { token: OptionChangesService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SpanColumnComponent, isStandalone: true, selector: "kendo-treelist-span-column", inputs: { expandable: "expandable", title: "title", headerClass: "headerClass", footerClass: "footerClass", headerStyle: "headerStyle", footerStyle: "footerStyle", editable: "editable", locked: "locked" }, providers: [
{
provide: ColumnBase,
useExisting: forwardRef(() => SpanColumnComponent)
}
], queries: [{ propertyName: "template", predicate: CellTemplateDirective }, { propertyName: "editTemplate", predicate: EditTemplateDirective }, { propertyName: "childColumns", predicate: ColumnComponent }], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpanColumnComponent, decorators: [{
type: Component,
args: [{
providers: [
{
provide: ColumnBase,
useExisting: forwardRef(() => SpanColumnComponent)
}
],
selector: 'kendo-treelist-span-column',
template: ``,
standalone: true
}]
}], ctorParameters: function () { return [{ type: ColumnBase, decorators: [{
type: SkipSelf
}, {
type: Host
}, {
type: Optional
}] }, { type: OptionChangesService }]; }, propDecorators: { expandable: [{
type: Input
}], title: [{
type: Input
}], headerClass: [{
type: Input
}], footerClass: [{
type: Input
}], headerStyle: [{
type: Input
}], footerStyle: [{
type: Input
}], template: [{
type: ContentChildren,
args: [CellTemplateDirective, { descendants: false }]
}], editTemplate: [{
type: ContentChildren,
args: [EditTemplateDirective, { descendants: false }]
}], childColumns: [{
type: ContentChildren,
args: [ColumnComponent]
}], editable: [{
type: Input
}], locked: [{
type: Input
}] } });
/**
* @hidden
*/
const expandColumns = (columns) => (columns.reduce((acc, column) => acc.concat(isSpanColumnComponent(column) ? column.childrenArray : [column]), []));
/**
* @hidden
*/
const expandColumnsWithSpan = (columns) => (columns.reduce((acc, column) => acc.concat(isSpanColumnComponent(column) ?
[column].concat(column.childrenArray) :
[column]), []));
/**
* @hidden
*/
const columnsToRender = (columns) => (expandColumns(columns).filter(x => x.isVisible));
const sumProp = (prop) => (array) => (array || []).reduce((prev, curr) => prev + (curr[prop] || 0), 0);
/**
* @hidden
*/
const sumColumnWidths = sumProp('width');
/**
* @hidden
*/
const columnsSpan = sumProp('colspan');
const validField = new RegExp(`^[$A-Z\_a-z][$A-Z\_a-z0-9\\.]*$`);
/**
* @hidden
*/
const isValidFieldName = (fieldName) => !isNullOrEmptyString(fieldName) && validField.test(fieldName) &&
fieldName[0] !== "." && fieldName[fieldName.length - 1] !== ".";
/**
* @hidden
*/
const children = column => column.children.filter(child => child !== column);
/**
* @hidden
*/
const leafColumns = columns => {
return columns.reduce((acc, column) => {
if (column.isColumnGroup) {
acc = acc.concat(leafColumns(children(column)));
}
else if (column.isSpanColumn) {
acc = acc.concat(column.childrenArray);
}
else {
acc.push(column);
}
return acc;
}, []).filter(x => x.isVisible);
};
/**
* @hidden
*/
const someLeafColumn = (callback, ...columns) => leafColumns(columns).some(callback);
/**
* @hidden
*/
const resizableColumns = columns => columns.filter(column => isTruthy(column.resizable) && column.isVisible);
/**
* @hidden
*/
const sortColumns = (columns) => orderBy(columns, [{ field: 'orderIndex', dir: 'asc' }]);
/**
* @hidden
*/
const isInSpanColumn$1 = (column) => isTruthy(column.parent) && isSpanColumnComponent(column.parent);
/**
* @hidden
*/
function isColumnGroupComponent(column) {
return column.isColumnGroup;
}
/**
* Represents the column group header of the TreeList. ([More information and examples]({% slug multicolumnheaders_columns_treelist %})).
*
* @example
* ```html
* <kendo-treelist ...>
* <kendo-treelist-column-group title="File Info">
* <kendo-treelist-column field="type" title="Type"> </kendo-treelist-column>
* <kendo-treelist-column field="size" title="Size"> </kendo-treelist-column>
* </kendo-treelist-column-group>
* </kendo-treelist>
* ```
*/
class ColumnGroupComponent extends ColumnBase {
/**
* @hidden
*/
includeInChooser = false;
/**
* @hidden
*/
isColumnGroup = true;
/**
* @hidden
*/
minResizableWidth = 10;
/**
* @hidden
*/
children;
constructor(parent, optionChanges) {
super(parent, optionChanges);
if (parent && parent.isSpanColumn) {
throw new Error('ColumnGroupComponent cannot be nested inside SpanColumnComponent');
}
}
/**
* @hidden
*/
rowspan() {
return 1;
}
/**
* @hidden
*/
get colspan() {
if (!this.children) {
return 1;
}
return columnsSpan(this.children
.filter(child => child !== this && child.isVisible));
}
/**
* @hidden
*/
get leafIndex() {
return this.children ? (this.firstChild || {}).leafIndex : -1;
}
get childrenArray() {
return this.children.filter(c => c !== this);
}
get hasChildren() {
return Boolean(this.firstChild);
}
get firstChild() {
return this.children.find(column => column !== this);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ColumnGroupComponent, deps: [{ token: ColumnBase, host: true, optional: true, skipSelf: true }, { token: OptionChangesService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ColumnGroupComponent, isStandalone: true, selector: "kendo-treelist-column-group", providers: [
{
provide: ColumnBase,
useExisting: forwardRef(() => ColumnGroupComponent)
}
], queries: [{ propertyName: "children", predicate: ColumnBase }], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "