UNPKG

@progress/kendo-angular-treeview

Version:
166 lines (165 loc) 6.91 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { anyChanged, isChanged } from '@progress/kendo-angular-common'; import { Directive, Input } from '@angular/core'; import { getter } from '@progress/kendo-common'; import { of } from 'rxjs'; import { compose } from './funcs'; import { DataBoundComponent } from './data-bound-component'; import { isBlank, isNullOrEmptyString, isPresent, isArrayWithAtLeastOneItem } from './utils'; import { FlatEditingService } from "./drag-and-drop/editing-services/flat-editing.service"; import { IndexBuilderService } from './index-builder.service'; import { FilteringBase } from './filtering-base'; import * as i0 from "@angular/core"; import * as i1 from "./data-bound-component"; const findChildren = (prop, nodes, value) => nodes.filter((x) => prop(x) === value); const indexBuilder = new IndexBuilderService(); const mapToTree = (currentLevelNodes, allNodes, parentIdField, idField, 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 = mapToTree(findChildren(getter(parentIdField), allNodes || [], getter(idField)(node)), allNodes, parentIdField, idField, wrapper, index); return wrapper; }); }; /** * Represents a directive that handles flat data binding and provides built-in filtering functionality for the TreeView. * * Use this directive to bind flat data where parent-child relationships are defined by ID fields. * The directive also enables the built-in filter input and automatic filter handling when used with the `filterable` property. * * @example * ```html * <kendo-treeview * kendoTreeViewFlatDataBinding * idField="id" * parentIdField="parentId" * textField="text" * [nodes]="data" * [filterable]="true"> * </kendo-treeview> * ``` * * @remarks * Applied to: {@link TreeViewComponent} */ export class FlatDataBindingDirective extends FilteringBase { component; /** * Specifies the flat data collection that renders as nodes in 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; /** * Specifies the field name that contains the parent node identifier. */ parentIdField; /** * Specifies the field name that contains the unique node identifier. */ idField; /** * @hidden */ loadOnDemand = true; /** * @hidden * A callback which determines whether a TreeView node should be rendered as hidden. */ set isVisible(fn) { this.component.isVisible = fn; } /** * @hidden */ originalData = []; constructor(component) { super(component); this.component = component; this.component.isVisible = (node) => this.visibleNodes.has(node); } /** * @hidden */ ngOnInit() { if (isPresent(this.parentIdField) && isPresent(this.idField)) { const fetchChildren = (node) => findChildren(getter(this.parentIdField), this.originalData || [], getter(this.idField)(node)); this.component.hasChildren = (node) => fetchChildren(node).length > 0; this.component.children = (node) => of(fetchChildren(node)); this.component.editService = new FlatEditingService(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(); } } } /** * @hidden */ ngOnChanges(changes) { if (isChanged('parentIdField', 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 || []; if (!isNullOrEmptyString(this.parentIdField)) { const prop = getter(this.parentIdField); this.component.nodes = this.originalData.filter(compose(isBlank, prop)); this.filterData = mapToTree(this.component.nodes, this.originalData, this.parentIdField, this.idField); this.updateVisibleNodes(this.filterData); } else { this.component.nodes = this.originalData.slice(0); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlatDataBindingDirective, deps: [{ token: i1.DataBoundComponent }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FlatDataBindingDirective, isStandalone: true, selector: "[kendoTreeViewFlatDataBinding]", inputs: { nodes: "nodes", parentIdField: "parentIdField", idField: "idField", loadOnDemand: "loadOnDemand", isVisible: "isVisible" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlatDataBindingDirective, decorators: [{ type: Directive, args: [{ selector: "[kendoTreeViewFlatDataBinding]", standalone: true }] }], ctorParameters: function () { return [{ type: i1.DataBoundComponent }]; }, propDecorators: { nodes: [{ type: Input }], parentIdField: [{ type: Input }], idField: [{ type: Input }], loadOnDemand: [{ type: Input }], isVisible: [{ type: Input }] } });