@progress/kendo-angular-treeview
Version:
Kendo UI TreeView for Angular
928 lines (927 loc) • 39.5 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 { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmitter, HostBinding, Input, NgZone, Output, Renderer2, ViewChild, ViewContainerRef, isDevMode, forwardRef, ChangeDetectorRef } from '@angular/core';
import { anyChanged, hasObservers, isDocumentAvailable } from '@progress/kendo-angular-common';
import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n';
import { BehaviorSubject, of, Subscription } from 'rxjs';
import { validatePackage } from '@progress/kendo-licensing';
import { packageMetadata } from './package-metadata';
import { DataChangeNotificationService } from './data-change-notification.service';
import { hasCheckbox, hasChildren, isChecked, isDisabled, isExpanded, isSelected, isVisible, trackBy } from './default-callbacks';
import { ExpandStateService } from './expand-state.service';
import { IndexBuilderService } from './index-builder.service';
import { LoadingNotificationService } from './loading-notification.service';
import { NavigationService } from './navigation/navigation.service';
import { NodeChildrenService } from './node-children.service';
import { NodeTemplateDirective } from './node-template.directive';
import { LoadMoreButtonTemplateDirective } from './load-more/load-more-button-template.directive';
import { DataBoundComponent } from './data-bound-component';
import { ExpandableComponent } from './expandable-component';
import { SelectionService } from './selection/selection.service';
import { TreeViewLookupService } from './treeview-lookup.service';
import { closestNode, focusableNode, hasParent, isContent, isFocusable, match, nodeId, isLoadMoreButton, isPresent, nodeIndex, buildTreeItem, getSizeClass } from './utils';
import { searchIcon } from '@progress/kendo-svg-icons';
import { TextBoxComponent, TextBoxPrefixTemplateDirective } from '@progress/kendo-angular-inputs';
import { TreeViewGroupComponent } from './treeview-group.component';
import { NgIf } from '@angular/common';
import { LocalizedMessagesDirective } from './localization/localized-messages.directive';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import * as i0 from "@angular/core";
import * as i1 from "./expand-state.service";
import * as i2 from "./navigation/navigation.service";
import * as i3 from "./node-children.service";
import * as i4 from "./selection/selection.service";
import * as i5 from "./treeview-lookup.service";
import * as i6 from "./data-change-notification.service";
import * as i7 from "@progress/kendo-angular-l10n";
let nextId = 0;
const LOAD_MORE_DOC_LINK = 'https://www.telerik.com/kendo-angular-ui/components/treeview/load-more-button/';
const providers = [
ExpandStateService,
IndexBuilderService,
TreeViewLookupService,
LoadingNotificationService,
NodeChildrenService,
NavigationService,
SelectionService,
DataChangeNotificationService,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.treeview'
},
{
provide: DataBoundComponent,
useExisting: forwardRef(() => TreeViewComponent)
},
{
provide: ExpandableComponent,
useExisting: forwardRef(() => TreeViewComponent)
}
];
/**
* Represents the [Kendo UI TreeView component for Angular]({% slug overview_treeview %}).
*
*/
export class TreeViewComponent {
element;
changeDetectorRef;
expandService;
navigationService;
nodeChildrenService;
selectionService;
treeViewLookupService;
ngZone;
renderer;
dataChangeNotification;
localization;
/**
* @hidden
*/
searchIcon = searchIcon;
classNames = true;
/** @hidden */
get direction() {
return this.localization.rtl ? 'rtl' : 'ltr';
}
/**
* @hidden
*/
assetsContainer;
/**
* @hidden
*/
searchbox;
/**
* The hint which is displayed when the component is empty.
*/
filterInputPlaceholder = "";
/**
* Determines whether to allow expanding disabled nodes.
* @default false
*/
expandDisabledNodes;
/**
* Determines whether the content animation is enabled.
*/
set animate(value) {
this._animate = value;
}
get animate() {
return !this._animate;
}
/** @hidden */
fetchNodes = () => this.data;
/**
* Fires when the children of the expanded node are loaded.
*/
childrenLoaded = new EventEmitter();
/**
* Fires when the user blurs the component.
*/
onBlur = new EventEmitter();
/**
* Fires when the user focuses the component.
*/
onFocus = new EventEmitter();
/**
* Fires when the user expands a TreeView node.
*/
expand = new EventEmitter();
/**
* Fires when the user collapses a TreeView node.
*/
collapse = new EventEmitter();
/**
* Fires just before the dragging of the node starts ([see example]({% slug draganddrop_treeview %}#toc-setup)). This event is preventable.
* If you prevent the event default, no drag hint will be created and the subsequent drag-related events will not be fired.
*/
nodeDragStart = new EventEmitter();
/**
* Fires when an item is being dragged ([see example]({% slug draganddrop_treeview %}#toc-setup)).
*/
nodeDrag = new EventEmitter();
/**
* Emits when the built-in filtering mechanism in the data-binding directives updates the node's visibility.
* Used for the built-in auto-expand functionalities of the component and available for custom implementations.
*/
filterStateChange = new EventEmitter();
/**
* Fires on the target TreeView when a dragged item is dropped ([see example]({% slug draganddrop_treeview %}#toc-setup)).
* This event is preventable. If you prevent the event default (`event.preventDefualt()`) or invalidate its state (`event.setValid(false)`),
* the `addItem` and `removeItem` events will not be triggered.
*
* Both operations cancel the default drop operation, but the indication to the user is different. `event.setValid(false)` indicates that the operation was
* unsuccessful by animating the drag clue to its original position. `event.preventDefault()` simply removes the clue, as if it has been dropped successfully.
* As a general rule, use `preventDefault` to manually handle the add and remove operations, and `setValid(false)` to indicate the operation was unsuccessful.
*/
nodeDrop = new EventEmitter();
/**
* Fires on the source TreeView after the dragged item has been dropped ([see example]({% slug draganddrop_treeview %}#toc-setup)).
*/
nodeDragEnd = new EventEmitter();
/**
* Fires after a dragged item is dropped ([see example]({% slug draganddrop_treeview %}#toc-setup)).
* Called on the TreeView where the item is dropped.
*/
addItem = new EventEmitter();
/**
* Fires after a dragged item is dropped ([see example]({% slug draganddrop_treeview %}#toc-setup)).
* Called on the TreeView from where the item is dragged.
*/
removeItem = new EventEmitter();
/**
* Fires when the user selects a TreeView node checkbox
* ([see example]({% slug checkboxes_treeview %}#toc-modifying-the-checked-state)).
*/
checkedChange = new EventEmitter();
/**
* Fires when the user selects a TreeView node
* ([see example]({% slug selection_treeview %}#toc-modifying-the-selection)).
*/
selectionChange = new EventEmitter();
/**
* Fires when the value of the built-in filter input element changes.
*/
filterChange = new EventEmitter();
/**
* Fires when the user clicks a TreeView node.
*/
nodeClick = new EventEmitter();
/**
* Fires when the user double clicks a TreeView node.
*/
nodeDblClick = new EventEmitter();
/**
* @hidden
*
* Queries the template for a node template declaration.
* Ignored if a `[nodeTemplate]` value is explicitly provided.
*/
nodeTemplateQuery;
/**
* @hidden
*
* Defines the template for each node.
* Takes precedence over nested templates in the TreeView tag.
*/
set nodeTemplateRef(template) {
this._nodeTemplateRef = template;
}
get nodeTemplateRef() {
return this._nodeTemplateRef || this.nodeTemplateQuery;
}
/**
* @hidden
*
* Queries the template for a load-more button template declaration.
* Ignored if a `[loadMoreButtonTemplate]` value is explicitly provided.
*/
loadMoreButtonTemplateQuery;
/**
* @hidden
*
* Defines the template for each load-more button.
* Takes precedence over nested templates in the TreeView tag.
*/
set loadMoreButtonTemplateRef(template) {
this._loadMoreButtonTemplateRef = template;
}
get loadMoreButtonTemplateRef() {
return this._loadMoreButtonTemplateRef || this.loadMoreButtonTemplateQuery;
}
/**
* A function that defines how to track node changes.
* By default, the TreeView tracks the nodes by data item object reference.
*
* @example
* ```ts
* @Component({
* selector: 'my-app',
* template: `
* <kendo-treeview
* [nodes]="data"
* textField="text"
* [trackBy]="trackBy"
* >
* </kendo-treeview>
* `
* })
* export class AppComponent {
* public data: any[] = [
* { text: "Furniture" },
* { text: "Decor" }
* ];
*
* public trackBy(index: number, item: any): any {
* return item.text;
* }
* }
* ```
*/
trackBy = trackBy;
/**
* The nodes which will be displayed by the TreeView
* ([see example]({% slug databinding_treeview %})).
*/
set nodes(value) {
this.data.next(value || []);
this.dataChangeNotification.notify();
}
get nodes() {
return this.data.value;
}
/**
* The fields of the data item that provide the text content of the nodes
* ([see example]({% slug databinding_treeview %})). If the `textField` input is set
* to an array, each hierarchical level uses the field that corresponds to the same
* index in the array, or the last item in the array.
*/
textField;
/**
* A function which determines if a specific node has child nodes
* ([see example]({% slug databinding_treeview %})).
*/
get hasChildren() {
return this._hasChildren || hasChildren;
}
set hasChildren(callback) {
this._hasChildren = callback;
this.expandIcons = Boolean(this._isExpanded && this._hasChildren);
}
/**
* A function which determines if a specific node is checked
* ([see example]({% slug checkboxes_treeview %}#toc-modifying-the-checked-state)).
*/
get isChecked() {
return this._isChecked || isChecked;
}
set isChecked(callback) {
this._isChecked = callback;
this.checkboxes = Boolean(this._isChecked);
}
/**
* A function which determines if a specific node is disabled.
*/
isDisabled = isDisabled;
/**
* A function which determines if a specific node has a checkbox.
*
* > If there is no checkbox for a node, then this node is not checkable and is excluded from any built-in check functionality.
*/
hasCheckbox = hasCheckbox;
/**
* A function which determines if a specific node is expanded.
*/
get isExpanded() {
return this._isExpanded || isExpanded;
}
set isExpanded(callback) {
this._isExpanded = callback;
this.expandIcons = Boolean(this._isExpanded && this._hasChildren);
}
/**
* A function which determines if a specific node is selected
* ([see example]({% slug selection_treeview %}#toc-modifying-the-selection)).
*/
get isSelected() {
return this._isSelected || isSelected;
}
set isSelected(callback) {
this._isSelected = callback;
this.selectable = Boolean(this._isSelected);
}
/**
* A callback which determines whether a TreeView node should be rendered as hidden. The utility .k-hidden class is used to hide the nodes.
* Useful for custom filtering implementations.
*/
isVisible = isVisible;
/**
* Determines whether the TreeView keyboard navigable is enabled.
*/
navigable = true;
/**
* A function which provides the child nodes for a given parent node
* ([see example]({% slug databinding_treeview %})).
*/
children = () => of([]);
/**
* Indicates whether the child nodes will be fetched on node expand or will be initially prefetched.
* @default true
*/
loadOnDemand = true;
/**
* Renders the built-in input element for filtering the TreeView.
* If set to `true`, the component emits the `filterChange` event, which can be used to [filter the TreeView manually]({% slug filtering_treeview %}#toc-manual-filtering).
* A built-in filtering implementation is available to use with the [`kendoTreeViewHierarchyBinding`]({% slug api_treeview_hierarchybindingdirective %}) and [`kendoTreeViewFlatDataBinding`]({% slug api_treeview_flatdatabindingdirective %}) directives.
*/
filterable = false;
/**
* Sets an initial value of the built-in input element used for filtering.
*/
filter = '';
/**
* Sets the size of the component.
*
* The possible values are:
* * `small`
* * `medium` (default)
* * `large`
* * `none`
*/
set size(size) {
const newSize = size ? size : 'medium';
if (this.size !== 'none') {
this.renderer.removeClass(this.element.nativeElement, getSizeClass('treeview', this.size));
}
this.renderer.addClass(this.element.nativeElement, getSizeClass('treeview', newSize));
this._size = size;
}
get size() {
return this._size;
}
get isActive() {
return this.navigationService.isTreeViewActive;
}
/**
* @hidden
*/
get treeviewId() {
return `treeview_${this._nextId}`;
}
/**
* Indicates whether only parent nodes should be disabled or their child nodes as well
* @default false
*/
disableParentNodesOnly = false;
/**
* @hidden
*/
loadMoreService;
/**
* @hidden
*/
editService;
checkboxes = false;
expandIcons = false;
selectable = false;
touchActions = true;
data = new BehaviorSubject([]);
_animate = true;
_isChecked;
_isExpanded;
_isSelected;
_hasChildren;
_nodeTemplateRef;
_loadMoreButtonTemplateRef;
_size = 'medium';
subscriptions = new Subscription();
domSubscriptions = [];
_nextId = nextId;
constructor(element, changeDetectorRef, expandService, navigationService, nodeChildrenService, selectionService, treeViewLookupService, ngZone, renderer, dataChangeNotification, localization) {
this.element = element;
this.changeDetectorRef = changeDetectorRef;
this.expandService = expandService;
this.navigationService = navigationService;
this.nodeChildrenService = nodeChildrenService;
this.selectionService = selectionService;
this.treeViewLookupService = treeViewLookupService;
this.ngZone = ngZone;
this.renderer = renderer;
this.dataChangeNotification = dataChangeNotification;
this.localization = localization;
validatePackage(packageMetadata);
nextId++;
}
ngOnChanges(changes) {
this.navigationService.navigable = Boolean(this.navigable);
// TODO: should react to changes.loadOnDemand as well - should preload the data or clear the already cached items
if (anyChanged(['nodes', 'children', 'hasChildren', 'loadOnDemand'], changes, false) && !this.loadOnDemand) {
this.preloadChildNodes();
}
}
ngOnDestroy() {
this.subscriptions.unsubscribe();
this.domSubscriptions.forEach(subscription => subscription());
}
ngOnInit() {
this.subscriptions.add(this.nodeChildrenService
.changes
.subscribe((x) => this.childrenLoaded.emit(x)));
this.subscriptions.add(this.expandService.changes
.subscribe(({ index, dataItem, expand }) => expand
? this.expand.emit({ index, dataItem })
: this.collapse.emit({ index, dataItem })));
this.subscriptions.add(this.navigationService.checks
.subscribe((x) => this.checkedChange.emit(this.treeViewLookupService.itemLookup(x))));
this.subscriptions.add(this.selectionService.changes
.subscribe((x) => {
if (hasObservers(this.selectionChange)) {
this.ngZone.run(() => {
this.selectionChange.emit(x);
});
}
}));
if (this.element) {
this.ngZone.runOutsideAngular(() => {
this.attachDomHandlers();
});
}
if (this.size) {
this.renderer.addClass(this.element.nativeElement, getSizeClass('treeview', this.size));
}
}
ngAfterViewInit() {
if (this.searchbox) {
this.renderer.setAttribute(this.searchbox.input.nativeElement, 'role', 'searchbox');
this.renderer.setAttribute(this.searchbox.input.nativeElement, 'aria-controls', this.treeviewId);
this.renderer.setAttribute(this.searchbox.input.nativeElement, 'aria-label', 'searchbar');
}
}
/**
* Blurs the focused TreeView item.
*/
blur() {
if (!isDocumentAvailable()) {
return;
}
const target = focusableNode(this.element);
if (document.activeElement === target) {
target.blur();
}
}
/**
* Focuses the first focusable item in the TreeView component if no hierarchical index is provided.
*
* @example
* ```ts
* import { Component } from '@angular/core';
*
* @Component({
* selector: 'my-app',
* template: `
* <button (click)="treeview.focus('1')">Focuses the second node</button>
* <kendo-treeview
* #treeview
* [nodes]="data"
* textField="text"
* >
* </kendo-treeview>
* `
* })
* export class AppComponent {
* public data: any[] = [
* { text: "Furniture" },
* { text: "Decor" }
* ];
* }
* ```
*/
focus(index) {
const focusIndex = index || nodeIndex(this.navigationService.focusableItem);
this.navigationService.activateIndex(focusIndex);
const target = focusableNode(this.element);
if (target) {
target.focus();
}
}
/**
* Based on the specified index, returns the TreeItemLookup node.
*
* @param index - The index of the node.
* @returns {TreeItemLookup} - The item that was searched (looked up).
*/
itemLookup(index) {
return this.treeViewLookupService.itemLookup(index);
}
/**
* Triggers the [`children`]({% slug api_treeview_treeviewcomponent %}#toc-children) function for every expanded node,
* causing all rendered child nodes to be fetched again.
*/
rebindChildren() {
this.dataChangeNotification.notify();
}
/**
* Triggers the `expand` event for the provided node and displays it's loading indicator.
*/
expandNode(item, index) {
this.expandService.expand(index, item);
}
/**
* Triggers the `collapse` event for the provided node.
*/
collapseNode(item, index) {
this.expandService.collapse(index, item);
}
/**
* Gets the current page size of the checked data item children collection
* ([see example]({% slug loadmorebutton_treeview %}#toc-managing-page-sizes)).
*
* > Since the root nodes collection is not associated with any parent data item, pass `null` as `dataItem` param to get its page size.
*
* @param dataItem {any} - The parent data item of the targeted collection.
* @returns {number} - The page size of the checked data item children collection.
*/
getNodePageSize(dataItem) {
this.verifyLoadMoreService();
return this.loadMoreService.getGroupSize(dataItem);
}
/**
* Sets the page size of the targeted data item children collection
* ([see example]({% slug loadmorebutton_treeview %}#toc-managing-page-sizes)).
*
* > Since the root nodes collection is not associated with any parent data item, pass `null` as `dataItem` param to target its page size.
*
* @param dataItem {any} - The parent data item of the targeted collection.
* @param pageSize {number} - The new page size.
*/
setNodePageSize(dataItem, pageSize) {
this.verifyLoadMoreService();
this.loadMoreService.setGroupSize(dataItem, pageSize);
}
/**
* @hidden
*
* Clears the current TreeViewLookupService node map and re-registers all nodes anew.
* Child nodes are acquired through the provided `children` callback.
*/
preloadChildNodes() {
this.treeViewLookupService.reset();
this.registerLookupItems(this.nodes);
}
attachDomHandlers() {
const element = this.element.nativeElement;
this.clickHandler = this.clickHandler.bind(this);
this.domSubscriptions.push(this.renderer.listen(element, 'contextmenu', this.clickHandler), this.renderer.listen(element, 'click', this.clickHandler), this.renderer.listen(element, 'dblclick', this.clickHandler), this.renderer.listen(element, 'focusin', this.focusHandler.bind(this)), this.renderer.listen(element, 'focusout', this.blurHandler.bind(this)), this.renderer.listen(element, 'keydown', this.keydownHandler.bind(this)));
}
focusHandler(e) {
let focusItem;
if (match(e.target, '.k-treeview-item')) {
focusItem = e.target;
}
else if (!isFocusable(e.target)) { // with compliments to IE
focusItem = closestNode(e.target);
}
if (focusItem) {
const nodeIndex = nodeId(e.target);
if (this.navigationService.isDisabled(nodeIndex)) {
return;
}
this.navigationService.activateIndex(nodeIndex);
if (!this.isActive && hasObservers(this.onFocus)) {
this.ngZone.run(() => {
this.onFocus.emit();
});
}
this.navigationService.isTreeViewActive = true;
}
}
blurHandler(e) {
if (this.isActive && match(e.target, '.k-treeview-item') &&
(!e.relatedTarget || !match(e.relatedTarget, '.k-treeview-item') || !hasParent(e.relatedTarget, this.element.nativeElement))) {
this.navigationService.deactivate();
this.navigationService.isTreeViewActive = false;
if (hasObservers(this.onBlur)) {
this.ngZone.run(() => {
this.onBlur.emit();
});
}
}
}
clickHandler(e) {
const target = e.target;
if ((e.type === 'contextmenu' && !hasObservers(this.nodeClick)) ||
(e.type === 'click' && !hasObservers(this.nodeClick) && !hasObservers(this.selectionChange) && !isLoadMoreButton(target)) ||
(e.type === 'dblclick' && !hasObservers(this.nodeDblClick)) || isFocusable(target) ||
(!isContent(target) && !isLoadMoreButton(target)) || !hasParent(target, this.element.nativeElement)) {
return;
}
const index = nodeId(closestNode(target));
// the disabled check is probably not needed due to the k-disabled styles
if (!index || this.navigationService.isDisabled(index)) {
return;
}
this.ngZone.run(() => {
// record this value before emitting selectionChange (`this.navigationService.selectIndex`), as the treeview state may be changed on its emission
const lookup = this.treeViewLookupService.itemLookup(index);
if (e.type === 'click') {
const loadMoreButton = this.navigationService.model.findNode(index).loadMoreButton;
if (loadMoreButton) {
this.navigationService.notifyLoadMore(index);
return;
}
else {
this.navigationService.selectIndex(index);
}
}
const emitter = e.type === 'dblclick' ? this.nodeDblClick : this.nodeClick;
emitter.emit({
item: lookup.item,
originalEvent: e,
type: e.type
});
});
}
keydownHandler(e) {
if (this.isActive && this.navigable) {
this.ngZone.run(() => {
this.navigationService.move(e);
});
}
}
verifyLoadMoreService() {
if (isDevMode() && !isPresent(this.loadMoreService)) {
throw new Error(`To use the TreeView paging functionality, you need to assign the \`kendoTreeViewLoadMore\` directive. See ${LOAD_MORE_DOC_LINK}.`);
}
}
registerLookupItems(data, parentItem = null) {
if (!isPresent(data) || data.length === 0) {
return;
}
const parentIndex = nodeIndex(parentItem);
const treeItems = data.map((node, index) => buildTreeItem(node, index, parentIndex));
if (isPresent(parentItem)) {
this.treeViewLookupService.registerChildren(parentIndex, treeItems);
}
treeItems.forEach(item => {
this.treeViewLookupService.registerItem(item, parentItem);
if (this.hasChildren(item.dataItem)) {
this.children(item.dataItem)
.subscribe(children => this.registerLookupItems(children, item));
}
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeViewComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1.ExpandStateService }, { token: i2.NavigationService }, { token: i3.NodeChildrenService }, { token: i4.SelectionService }, { token: i5.TreeViewLookupService }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i6.DataChangeNotificationService }, { token: i7.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TreeViewComponent, isStandalone: true, selector: "kendo-treeview", inputs: { filterInputPlaceholder: "filterInputPlaceholder", expandDisabledNodes: "expandDisabledNodes", animate: "animate", nodeTemplateRef: ["nodeTemplate", "nodeTemplateRef"], loadMoreButtonTemplateRef: ["loadMoreButtonTemplate", "loadMoreButtonTemplateRef"], trackBy: "trackBy", nodes: "nodes", textField: "textField", hasChildren: "hasChildren", isChecked: "isChecked", isDisabled: "isDisabled", hasCheckbox: "hasCheckbox", isExpanded: "isExpanded", isSelected: "isSelected", isVisible: "isVisible", navigable: "navigable", children: "children", loadOnDemand: "loadOnDemand", filterable: "filterable", filter: "filter", size: "size", disableParentNodesOnly: "disableParentNodesOnly" }, outputs: { childrenLoaded: "childrenLoaded", onBlur: "blur", onFocus: "focus", expand: "expand", collapse: "collapse", nodeDragStart: "nodeDragStart", nodeDrag: "nodeDrag", filterStateChange: "filterStateChange", nodeDrop: "nodeDrop", nodeDragEnd: "nodeDragEnd", addItem: "addItem", removeItem: "removeItem", checkedChange: "checkedChange", selectionChange: "selectionChange", filterChange: "filterChange", nodeClick: "nodeClick", nodeDblClick: "nodeDblClick" }, host: { properties: { "class.k-treeview": "this.classNames", "attr.dir": "this.direction", "@.disabled": "this.animate" } }, providers: providers, queries: [{ propertyName: "nodeTemplateQuery", first: true, predicate: NodeTemplateDirective, descendants: true }, { propertyName: "loadMoreButtonTemplateQuery", first: true, predicate: LoadMoreButtonTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "assetsContainer", first: true, predicate: ["assetsContainer"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "searchbox", first: true, predicate: ["searchbox"], descendants: true }], exportAs: ["kendoTreeView"], usesOnChanges: true, ngImport: i0, template: `
<ng-container kendoTreeViewLocalizedMessages
i18n-loadMore="kendo.treeview.loadMore|The title of the Load More button"
loadMore="Load more..."
>
</ng-container>
<span
class="k-treeview-filter"
*ngIf="filterable"
>
<kendo-textbox
#searchbox
[size]="size"
[value]="filter"
[clearButton]="true"
(valueChange)="filterChange.emit($event)"
[placeholder]="filterInputPlaceholder"
>
<ng-template kendoTextBoxPrefixTemplate>
<kendo-icon-wrapper
innerCssClass="k-input-icon"
name="search"
[svgIcon]="searchIcon"
>
</kendo-icon-wrapper>
</ng-template>
</kendo-textbox>
</span>
<ul class="k-treeview-lines"
kendoTreeViewGroup
[attr.id]="treeviewId"
role="tree"
[size]="size"
[loadOnDemand]="loadOnDemand"
[checkboxes]="checkboxes"
[expandIcons]="expandIcons"
[selectable]="selectable"
[touchActions]="touchActions"
[children]="children"
[hasChildren]="hasChildren"
[isChecked]="isChecked"
[isDisabled]="isDisabled"
[hasCheckbox]="hasCheckbox"
[disableParentNodesOnly]="disableParentNodesOnly"
[isExpanded]="isExpanded"
[isSelected]="isSelected"
[isVisible]="isVisible"
[nodeTemplateRef]="nodeTemplateRef?.templateRef"
[loadMoreButtonTemplateRef]="loadMoreButtonTemplateRef?.templateRef"
[textField]="textField"
[nodes]="fetchNodes"
[loadMoreService]="loadMoreService"
[trackBy]="trackBy"
[expandDisabledNodes]="expandDisabledNodes"
>
</ul>
<ng-container #assetsContainer></ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoTreeViewLocalizedMessages]" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "directive", type: TextBoxPrefixTemplateDirective, selector: "[kendoTextBoxPrefixTemplate]", inputs: ["showSeparator"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: TreeViewGroupComponent, selector: "[kendoTreeViewGroup]", inputs: ["checkboxes", "expandIcons", "disabled", "selectable", "touchActions", "disableParentNodesOnly", "loadOnDemand", "trackBy", "nodes", "textField", "parentDataItem", "parentIndex", "nodeTemplateRef", "loadMoreButtonTemplateRef", "loadMoreService", "size", "expandDisabledNodes", "isChecked", "isDisabled", "hasCheckbox", "isExpanded", "isVisible", "isSelected", "children", "hasChildren"] }], changeDetection: i0.ChangeDetectionStrategy.Default });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TreeViewComponent, decorators: [{
type: Component,
args: [{
changeDetection: ChangeDetectionStrategy.Default,
exportAs: 'kendoTreeView',
providers: providers,
selector: 'kendo-treeview',
template: `
<ng-container kendoTreeViewLocalizedMessages
i18n-loadMore="kendo.treeview.loadMore|The title of the Load More button"
loadMore="Load more..."
>
</ng-container>
<span
class="k-treeview-filter"
*ngIf="filterable"
>
<kendo-textbox
#searchbox
[size]="size"
[value]="filter"
[clearButton]="true"
(valueChange)="filterChange.emit($event)"
[placeholder]="filterInputPlaceholder"
>
<ng-template kendoTextBoxPrefixTemplate>
<kendo-icon-wrapper
innerCssClass="k-input-icon"
name="search"
[svgIcon]="searchIcon"
>
</kendo-icon-wrapper>
</ng-template>
</kendo-textbox>
</span>
<ul class="k-treeview-lines"
kendoTreeViewGroup
[attr.id]="treeviewId"
role="tree"
[size]="size"
[loadOnDemand]="loadOnDemand"
[checkboxes]="checkboxes"
[expandIcons]="expandIcons"
[selectable]="selectable"
[touchActions]="touchActions"
[children]="children"
[hasChildren]="hasChildren"
[isChecked]="isChecked"
[isDisabled]="isDisabled"
[hasCheckbox]="hasCheckbox"
[disableParentNodesOnly]="disableParentNodesOnly"
[isExpanded]="isExpanded"
[isSelected]="isSelected"
[isVisible]="isVisible"
[nodeTemplateRef]="nodeTemplateRef?.templateRef"
[loadMoreButtonTemplateRef]="loadMoreButtonTemplateRef?.templateRef"
[textField]="textField"
[nodes]="fetchNodes"
[loadMoreService]="loadMoreService"
[trackBy]="trackBy"
[expandDisabledNodes]="expandDisabledNodes"
>
</ul>
<ng-container #assetsContainer></ng-container>
`,
standalone: true,
imports: [LocalizedMessagesDirective, NgIf, TextBoxComponent, TextBoxPrefixTemplateDirective, IconWrapperComponent, TreeViewGroupComponent]
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1.ExpandStateService }, { type: i2.NavigationService }, { type: i3.NodeChildrenService }, { type: i4.SelectionService }, { type: i5.TreeViewLookupService }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i6.DataChangeNotificationService }, { type: i7.LocalizationService }]; }, propDecorators: { classNames: [{
type: HostBinding,
args: ["class.k-treeview"]
}], direction: [{
type: HostBinding,
args: ["attr.dir"]
}], assetsContainer: [{
type: ViewChild,
args: ['assetsContainer', { read: ViewContainerRef, static: true }]
}], searchbox: [{
type: ViewChild,
args: ['searchbox']
}], filterInputPlaceholder: [{
type: Input
}], expandDisabledNodes: [{
type: Input
}], animate: [{
type: Input
}, {
type: HostBinding,
args: ['@.disabled']
}], childrenLoaded: [{
type: Output
}], onBlur: [{
type: Output,
args: ['blur']
}], onFocus: [{
type: Output,
args: ['focus']
}], expand: [{
type: Output
}], collapse: [{
type: Output
}], nodeDragStart: [{
type: Output
}], nodeDrag: [{
type: Output
}], filterStateChange: [{
type: Output
}], nodeDrop: [{
type: Output
}], nodeDragEnd: [{
type: Output
}], addItem: [{
type: Output
}], removeItem: [{
type: Output
}], checkedChange: [{
type: Output
}], selectionChange: [{
type: Output
}], filterChange: [{
type: Output
}], nodeClick: [{
type: Output
}], nodeDblClick: [{
type: Output
}], nodeTemplateQuery: [{
type: ContentChild,
args: [NodeTemplateDirective, { static: false }]
}], nodeTemplateRef: [{
type: Input,
args: ['nodeTemplate']
}], loadMoreButtonTemplateQuery: [{
type: ContentChild,
args: [LoadMoreButtonTemplateDirective, { static: false }]
}], loadMoreButtonTemplateRef: [{
type: Input,
args: ['loadMoreButtonTemplate']
}], trackBy: [{
type: Input
}], nodes: [{
type: Input
}], textField: [{
type: Input
}], hasChildren: [{
type: Input
}], isChecked: [{
type: Input
}], isDisabled: [{
type: Input
}], hasCheckbox: [{
type: Input
}], isExpanded: [{
type: Input
}], isSelected: [{
type: Input
}], isVisible: [{
type: Input
}], navigable: [{
type: Input
}], children: [{
type: Input
}], loadOnDemand: [{
type: Input
}], filterable: [{
type: Input
}], filter: [{
type: Input
}], size: [{
type: Input
}], disableParentNodesOnly: [{
type: Input
}] } });