UNPKG

@progress/kendo-angular-treeview

Version:
165 lines (164 loc) 7 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Directive, Input, Optional, Host } from '@angular/core'; import { getter } from '@progress/kendo-common'; import { anyChanged, isChanged } from '@progress/kendo-angular-common'; import { DataBoundComponent } from './data-bound-component'; import { isArrayWithAtLeastOneItem, isPresent } from './utils'; import { of } from 'rxjs'; import { HierarchyEditingService } from './drag-and-drop/editing-services/hierarchy-editing.service'; import { DragAndDropDirective } from './drag-and-drop/drag-and-drop.directive'; import { isVisible } from './default-callbacks'; import { IndexBuilderService } from './index-builder.service'; import { FilteringBase } from './filtering-base'; import * as i0 from "@angular/core"; import * as i1 from "./data-bound-component"; import * as i2 from "./drag-and-drop/drag-and-drop.directive"; const indexBuilder = new IndexBuilderService(); const mapToWrappers = (currentLevelNodes, childrenField, parent = null, parentIndex = '') => { if (!isArrayWithAtLeastOneItem(currentLevelNodes)) { return []; } return currentLevelNodes.map((node, idx) => { const index = indexBuilder.nodeIndex(idx.toString(), parentIndex); const wrapper = { dataItem: node, index, parent, visible: true }; wrapper.children = mapToWrappers(getter(childrenField)(node), childrenField, wrapper, index); return wrapper; }); }; /** * Represents a directive that handles hierarchical data binding and provides built-in filtering functionality for the TreeView. * * Use this directive to bind hierarchical data where child nodes are nested within parent nodes. * The directive also enables the built-in filter input and automatic filter handling when used with the `filterable` property. * * @example * ```html * <kendo-treeview * kendoTreeViewHierarchyBinding * childrenField="items" * textField="text" * [nodes]="data" * [filterable]="true"> * </kendo-treeview> * ``` * * @remarks * Applied to: {@link TreeViewComponent} */ export class HierarchyBindingDirective extends FilteringBase { component; dragAndDropDirective; /** * Specifies the field name of the parent node that holds the child data items. */ set childrenField(value) { if (!value) { throw new Error("'childrenField' cannot be empty"); } this._childrenField = value; } /** * Specifies the field name of the parent node that holds the child data items. */ get childrenField() { return this._childrenField; } /** * Specifies the hierarchical data displayed by the TreeView. */ set nodes(nodes) { // Needs to be a setter so that it can be accessed via `super` call (typescript v5) this._nodes = nodes; } get nodes() { return this._nodes; } _nodes; /** * @hidden * A callback which determines whether a TreeView node should be rendered as hidden. */ set isVisible(fn) { this.component.isVisible = fn; } /** * @hidden */ loadOnDemand = true; _childrenField; originalData = []; constructor(component, dragAndDropDirective) { super(component); this.component = component; this.dragAndDropDirective = dragAndDropDirective; const shouldFilter = !isPresent(this.dragAndDropDirective); this.component.isVisible = shouldFilter ? (node) => this.visibleNodes.has(node) : isVisible; } ngOnInit() { if (isPresent(this.childrenField)) { this.component.children = item => of(getter(this.childrenField)(item)); this.component.hasChildren = item => { const children = getter(this.childrenField)(item); return Boolean(children && children.length); }; this.component.editService = new HierarchyEditingService(this); this.component.filterChange.subscribe(this.handleFilterChange.bind(this)); if (this.component.filter) { this.handleFilterChange(this.component.filter); } if (!this.loadOnDemand && isPresent(this.component.preloadChildNodes)) { this.component.preloadChildNodes(); } } } ngOnChanges(changes) { if (isChanged('childrenField', changes, false)) { this.nodes = this.originalData; this.updateNodes(this.originalData); } if (isChanged('nodes', changes, false)) { this.updateNodes(changes['nodes'].currentValue); } // should react to changes.loadOnDemand as well - should preload the data or clear the already cached items if (anyChanged(['nodes', 'loadOnDemand'], changes) && !this.loadOnDemand && isPresent(this.component.preloadChildNodes)) { this.component.preloadChildNodes(); } } /** * @hidden */ updateNodes(values) { this.originalData = values || []; this.filterData = mapToWrappers(values, this.childrenField) || []; this.updateVisibleNodes(this.filterData); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HierarchyBindingDirective, deps: [{ token: i1.DataBoundComponent }, { token: i2.DragAndDropDirective, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HierarchyBindingDirective, isStandalone: true, selector: "[kendoTreeViewHierarchyBinding]", inputs: { childrenField: "childrenField", nodes: "nodes", isVisible: "isVisible", loadOnDemand: "loadOnDemand" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HierarchyBindingDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoTreeViewHierarchyBinding]', standalone: true }] }], ctorParameters: function () { return [{ type: i1.DataBoundComponent }, { type: i2.DragAndDropDirective, decorators: [{ type: Optional }, { type: Host }] }]; }, propDecorators: { childrenField: [{ type: Input }], nodes: [{ type: Input }], isVisible: [{ type: Input }], loadOnDemand: [{ type: Input }] } });