UNPKG

@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.

181 lines (180 loc) 6.34 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Input, Directive } from '@angular/core'; import { Subscription } from 'rxjs'; import { process, aggregateBy } from '@progress/kendo-data-query'; import { isChanged } from '@progress/kendo-angular-common'; import { DataBoundTreeComponent } from './data-bound-tree-component'; import { anyChanged } from '../utils'; import { RowReorderService } from './../row-reordering/row-reorder.service'; import * as i0 from "@angular/core"; import * as i1 from "./data-bound-tree-component"; import * as i2 from "./../row-reordering/row-reorder.service"; /** * @hidden */ export class BaseBindingDirective { component; rowReorderService; /** * Sets the descriptors that sort the data. */ set sort(value) { this.component.sort = this.state.sort = value; } /** * Sets the descriptor that filters the data. */ set filter(value) { this.component.filter = this.state.filter = value; } /** * Sets the descriptor that aggregates the data. */ set aggregate(value) { this._aggregate = value; } state = {}; dataChanged; cache = new Map(); originalData = []; _aggregate; subscriptions = new Subscription(); constructor(component, rowReorderService) { this.component = component; this.rowReorderService = rowReorderService; this.component.fetchChildren = this.fetchChildren.bind(this); this.component.hasChildren = this.hasChildren.bind(this); } /** * @hidden */ ngOnInit() { this.applyState(this.state); this.subscriptions.add(this.component.dataStateChange .subscribe(this.onStateChange.bind(this))); this.component.rowReorderable && this.subscriptions.add(this.rowReorderService.rowReorder .subscribe(this.onRowReorder.bind(this))); } /** * @hidden */ ngOnDestroy() { if (this.subscriptions) { this.subscriptions.unsubscribe(); } } ngDoCheck() { if (this.dataChanged) { this.dataChanged = false; this.rebind(); } } /** * @hidden */ ngOnChanges(changes) { if (anyChanged(['sort', 'filter', 'aggregate'], changes)) { this.rebind(); } if (isChanged('data', changes, false)) { this.updateData(changes['data'].currentValue); } } /** * @hidden */ onStateChange(state) { this.applyState(state); this.rebind(); } /** * Clears the directive cache and reloads the component data. */ rebind() { this.cache.clear(); this.component.data = this.fetchChildren(); } onRowReorder(_event) { } applyState({ sort, filter }) { this.sort = sort; this.filter = filter; } fetchChildren(item) { const key = this.itemKey(item); if (this.cache.has(key)) { return this.cache.get(key); } const children = this.getChildren(item); let items = this.filterItems(children); let aggregates; if (items.length) { if (this.state.sort) { items = process(items, { sort: this.state.sort }).data; } if (this._aggregate) { aggregates = this.calculateAggregates(items); } } const result = { data: items, aggregates: aggregates }; this.cache.set(key, result); return result; } hasChildren(item) { const items = this.fetchChildren(item).data; return items && items.length > 0; } filterItems(items) { const filter = this.state.filter; const hasFilter = filter && filter.filters && filter.filters.length > 0; if (hasFilter) { const filter = { logic: 'or', filters: [this.state.filter, { operator: (item) => { const children = this.fetchChildren(item); return Boolean(children.data && children.data.length); } }] }; return process(items, { filter: filter }).data; } return items; } calculateAggregates(items) { const list = []; const toAdd = items.slice(0); while (toAdd.length) { const current = toAdd.shift(); list.push(current); if (this.hasChildren(current)) { toAdd.push(...this.fetchChildren(current).data); } } // can accumulate from children aggregates except for average // for average we need the children count that have numeric value // maybe move the aggregates implementation here ??? return aggregateBy(list, this._aggregate); } updateData(value) { this.originalData = value || []; this.dataChanged = true; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BaseBindingDirective, deps: [{ token: i1.DataBoundTreeComponent }, { token: i2.RowReorderService }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: BaseBindingDirective, inputs: { sort: "sort", filter: "filter", aggregate: "aggregate" }, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BaseBindingDirective, decorators: [{ type: Directive, args: [{}] }], ctorParameters: function () { return [{ type: i1.DataBoundTreeComponent }, { type: i2.RowReorderService }]; }, propDecorators: { sort: [{ type: Input }], filter: [{ type: Input }], aggregate: [{ type: Input }] } });