@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.
618 lines (615 loc) • 30.1 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 { Component, Input, NgZone, Renderer2, ElementRef, HostBinding } from '@angular/core';
import { ChangeNotificationService } from '../data/change-notification.service';
import { isChanged, isPresent } from '../utils';
import { NoRecordsTemplateDirective } from './no-records-template.directive';
import { EditService } from '../editing/edit.service';
import { LocalizationService } from '@progress/kendo-angular-l10n';
import { columnsSpan } from "../columns/column-common";
import { closest, closestInScope, hasClasses, isFocusableWithTabKey, matchesClasses, matchesNodeName } from './common/dom-queries';
import { DomEventsService } from '../common/dom-events.service';
import { ColumnInfoService } from "../common/column-info.service";
import { hasFilterRow } from '../filtering/filterable';
import { NavigationService } from '../navigation/navigation.service';
import { Keys } from '@progress/kendo-angular-common';
import { defaultTrackBy } from '../common/default-track-by';
import { ExpandStateService } from '../expand-state/expand-state.service';
import { SelectionService } from '../selection/selection.service';
import { NON_DATA_CELL_CLASSES, NON_DATA_ROW_CLASSES, IGNORE_CONTAINER_CLASSES, ICON_CLASS, EMPTY_ICON_CLASS, DRAG_HANDLE_CLASS } from './constants';
import { ColumnsContainer } from '../columns/columns-container';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import { LevelItemsPipe } from './common/level-items.pipe';
import { LogicalCellDirective } from '../navigation/logical-cell.directive';
import { CellComponent } from './cell.component';
import { LogicalRowDirective } from '../navigation/logical-row.directive';
import { NgIf, NgTemplateOutlet, NgFor, NgClass, NgStyle } from '@angular/common';
import * as i0 from "@angular/core";
import * as i1 from "../data/change-notification.service";
import * as i2 from "../editing/edit.service";
import * as i3 from "@progress/kendo-angular-l10n";
import * as i4 from "../common/dom-events.service";
import * as i5 from "../common/column-info.service";
import * as i6 from "../navigation/navigation.service";
import * as i7 from "../expand-state/expand-state.service";
import * as i8 from "../selection/selection.service";
const columnCellIndex = (cell, cells) => {
for (let idx = 0; idx < cells.length; idx++) {
if (cells[idx] === cell) {
return idx;
}
}
};
/**
* @hidden
*/
export class TableBodyComponent {
changeNotification;
editService;
localization;
ngZone;
renderer;
element;
domEvents;
columnInfoService;
navigationService;
expandState;
selection;
hostClass = true;
columns = [];
allColumns;
noRecordsTemplate;
view;
skip = 0;
filterable;
noRecordsText;
isLocked = false;
lockedColumnsCount = 0;
totalColumnsCount = 0;
virtualColumns;
expandIcons;
trackBy = defaultTrackBy;
totalColumns;
noneIcon = {
name: 'none',
content: '',
viewBox: '0 0 24 24'
};
clickSubscription;
l10nSubscription;
cellKeydownSubscription;
clickTimeout;
headerOffset;
rowClass = () => null;
constructor(changeNotification, editService, localization, ngZone, renderer, element, domEvents, columnInfoService, navigationService, expandState, selection) {
this.changeNotification = changeNotification;
this.editService = editService;
this.localization = localization;
this.ngZone = ngZone;
this.renderer = renderer;
this.element = element;
this.domEvents = domEvents;
this.columnInfoService = columnInfoService;
this.navigationService = navigationService;
this.expandState = expandState;
this.selection = selection;
this.cellKeydownSubscription = this.navigationService.cellKeydown.subscribe((args) => this.cellKeydownHandler(args));
this.trackByWrapper = this.trackByWrapper.bind(this);
this.trackByColumns = this.trackByColumns.bind(this);
this.noRecordsText = this.localization.get('noRecords');
this.selection.registerTable(this);
}
get newDataItem() {
return this.editService.newDataItem;
}
// Number of unlocked columns in the next table, if any
unlockedColumnsCount(item) {
const allColumns = this.allColumns || this.columns;
let allColumnsCount = allColumns.length;
allColumns.forEach(column => {
if (column.isSpanColumn) {
allColumnsCount += column.colspan - 1;
}
});
const contentColumnsCount = this.totalColumnsCount - this.lockedColumnsCount - allColumnsCount;
const headerFooterColumnsCount = this.totalColumnsCount - this.lockedColumnsCount - (this.allColumns || this.columns).length;
return item && item.type === 'data' ? contentColumnsCount : headerFooterColumnsCount;
}
get hasData() {
const view = this.view;
return view && view.data !== null && view.data !== undefined && view.data.length > 0;
}
isOdd(item) {
return item.index % 2 !== 0;
}
trackByWrapper(index, item) {
if (item.type === 'data') {
item.isEditing = this.editService.isEdited(item.data);
}
return this.trackBy(index, item);
}
trackByColumns(index, item) {
return this.virtualColumns ? index : item;
}
ngOnChanges(changes) {
if (isChanged("columns", changes, false)) {
this.changeNotification.notify();
}
}
addRowLogicalIndex() {
return this.columnInfoService.totalLevels + 1;
}
logicalColIndex(column) {
if (!isPresent(column.leafIndex)) {
return -1;
}
return column.leafIndex;
}
cellExpandable(item, column) {
if (!column.expandable || !item.hasChildren) {
return false;
}
return true;
}
ariaRowExpanded(item) {
return this.lockedColumnsCount < 1 ? Boolean(item.expanded) : undefined;
}
ariaRowSelected(item) {
return this.lockedColumnsCount < 1 ? Boolean(item.selected) : undefined;
}
ariaExpanded(item, column) {
if (!column.expandable || !item.hasChildren) {
return;
}
return Boolean(item.expanded);
}
ariaSelected(item, column, columnIndex) {
if (!this.selection.enabled) {
return;
}
return item.selected || this.isCellSelected(item.data, column, columnIndex);
}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
const clickHandler = this.clickHandler.bind(this);
const mousedownSubscription = this.renderer.listen(this.element.nativeElement, 'mousedown', clickHandler);
const clickSubscription = this.renderer.listen(this.element.nativeElement, 'click', clickHandler);
const contextmenuSubscription = this.renderer.listen(this.element.nativeElement, 'contextmenu', clickHandler);
this.clickSubscription = () => {
mousedownSubscription();
clickSubscription();
contextmenuSubscription();
};
});
let originalNoRecordText = this.localization.get('noRecords');
this.l10nSubscription = this.localization.changes.subscribe(() => {
if (this.noRecordsText === originalNoRecordText) {
this.noRecordsText = this.localization.get('noRecords');
originalNoRecordText = this.noRecordsText;
}
});
}
ngDoCheck() {
this.headerOffset = this.columnInfoService.totalLevels + (hasFilterRow(this.filterable) ? 1 : 0);
}
ngOnDestroy() {
if (this.clickSubscription) {
this.clickSubscription();
}
if (this.l10nSubscription) {
this.l10nSubscription.unsubscribe();
}
this.cellKeydownSubscription.unsubscribe();
this.selection.unregisterTable(this);
clearTimeout(this.clickTimeout);
}
isEditingCell(item, column) {
return Boolean(item.editContext && this.editService.isEditingColumn(column));
}
isEditingRow(item) {
return Boolean(item.editContext) || item.isNew;
}
get columnsContainer() {
return this.columnInfoService.columnsContainer;
}
get hasFooter() {
return this.columnsContainer.hasFooter;
}
get columnsSpan() {
return columnsSpan(this.columns);
}
get allColumnsSpan() {
return columnsSpan(this.allColumns || this.columns);
}
get colSpan() {
return this.columnsSpan;
}
get footerColumns() {
return this.isLocked ? this.columnsContainer.lockedColumnsToRender : this.columnsContainer.nonLockedColumnsToRender;
}
logicalRowIndex(rowIndex) {
return 1 + rowIndex + this.headerOffset;
}
isCellSelected(dataItem, column, columnIndex) {
return this.selection.isCellSelected(dataItem, column, columnIndex);
}
targetArgs(target, skipFocusable) {
const { cell, row } = this.targetElements(target);
if (cell && (!skipFocusable || target === cell || !isFocusableWithTabKey(target, false))) {
const index = columnCellIndex(cell, row.cells);
const column = this.columns.toArray()[index];
const columnIndex = this.lockedColumnsCount + index;
return {
item: this.rowItem(row),
column: column,
columnIndex: columnIndex
};
}
}
checkIfClickable(target, cell) {
return !matchesNodeName('label')(target) &&
(!hasClasses(target, ICON_CLASS) || hasClasses(target, EMPTY_ICON_CLASS)) &&
!closestInScope(target, matchesClasses(IGNORE_CONTAINER_CLASSES), cell);
}
clickHandler(eventArg) {
const target = eventArg.target;
const { cell, row } = this.targetElements(target);
const forbiddenCellClasses = NON_DATA_CELL_CLASSES.concat(` ${DRAG_HANDLE_CLASS}`);
const isValidCell = cell ? !hasClasses(cell, forbiddenCellClasses) : false;
const isValidRow = row ? !hasClasses(row, NON_DATA_ROW_CLASSES) : false;
if (isValidRow && isValidCell) {
if (this.expandClick(eventArg, row) || this.checkboxClick(cell, row, eventArg) && !this.selection.dragging) {
return;
}
this.editService.preventCellClose();
const focusable = target !== cell && isFocusableWithTabKey(target, false);
const targetClickable = this.checkIfClickable(target, cell);
if (!focusable && targetClickable) {
const args = this.cellClickArgs(cell, row, eventArg);
if (!args) {
return;
}
if (eventArg.type === 'mousedown') {
this.domEvents.cellMousedown.emit(args);
}
else {
if (args.isEditedColumn || !this.editService.closeCell(eventArg)) {
if (eventArg.type === 'click') {
this.clickTimeout = setTimeout(() => {
this.emitCellClick(args);
}, 0);
}
else {
this.emitCellClick(args);
}
}
}
}
}
}
emitCellClick(args) {
this.domEvents.cellClick.emit(args);
}
cellKeydownHandler(args) {
if (args.keyCode === Keys.Enter) {
this.clickHandler(args);
}
}
cellClickArgs(cell, row, eventArg) {
const index = columnCellIndex(cell, row.cells);
const column = this.columns.toArray()[index];
const columnIndex = this.lockedColumnsCount + index;
const viewItem = this.rowItem(row);
if (viewItem.type !== 'data') {
return;
}
const type = eventArg.type === 'keydown' ? 'click' : eventArg.type;
return {
column: column,
columnIndex: columnIndex,
viewItem: viewItem,
dataItem: viewItem.data,
rowIndex: viewItem.index,
index: viewItem.index,
isEditedColumn: (viewItem.editContext && this.editService.isEditingColumn(column)),
isEdited: viewItem.isNew || (viewItem.editContext && this.editService.isEditedColumn(column)),
originalEvent: eventArg,
type: type
};
}
targetElements(target) {
const element = this.element.nativeElement;
let cell, row, body, treelistElement;
let currentTarget = target;
do {
cell = closest(currentTarget, matchesNodeName('td'));
row = closest(cell, matchesNodeName('tr'));
body = closest(row, matchesNodeName('tbody'));
currentTarget = body;
treelistElement = closestInScope(currentTarget, matchesClasses('k-treelist k-grid'), element);
} while (body && body !== element && !treelistElement);
if (cell && body === element && !treelistElement) {
return {
cell,
row
};
}
return {};
}
expandClick(eventArg, row) {
if (eventArg.type === 'click' && !hasClasses(eventArg.target, EMPTY_ICON_CLASS) && eventArg.target.closest('.k-treelist-toggle')) {
eventArg.preventDefault();
const viewItem = this.rowItem(row);
if (viewItem.type === 'data') {
this.ngZone.run(() => {
this.expandState.toggleState(viewItem.data);
});
return true;
}
}
}
checkboxClick(cell, row, eventArg) {
const isCheckboxCell = hasClasses(cell, 'k-checkbox-cell');
const isCheckbox = eventArg.target.closest('.k-checkbox-wrap');
if (isCheckboxCell && !isCheckbox && this.selection.settings.checkboxOnly) {
return;
}
if (eventArg.type === 'click' && isCheckboxCell &&
this.selection.enabled && this.selection.rowSelection) {
const args = this.cellClickArgs(cell, row, eventArg);
this.selection.checkboxClick(args);
if (eventArg.target.checked !== this.selection.isRowSelected(args.dataItem)) {
eventArg.preventDefault();
}
return true;
}
}
rowItem(row) {
let viewIndex = row.getAttribute('data-treelist-view-index');
viewIndex = viewIndex ? parseInt(viewIndex, 10) : -1;
const viewItem = this.view.at(viewIndex);
return viewItem;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TableBodyComponent, deps: [{ token: i1.ChangeNotificationService }, { token: i2.EditService }, { token: i3.LocalizationService }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i4.DomEventsService }, { token: i5.ColumnInfoService }, { token: i6.NavigationService }, { token: i7.ExpandStateService }, { token: i8.SelectionService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TableBodyComponent, isStandalone: true, selector: "[kendoTreeListTableBody]", inputs: { columns: "columns", allColumns: "allColumns", noRecordsTemplate: "noRecordsTemplate", view: "view", skip: "skip", filterable: "filterable", noRecordsText: "noRecordsText", isLocked: "isLocked", lockedColumnsCount: "lockedColumnsCount", totalColumnsCount: "totalColumnsCount", virtualColumns: "virtualColumns", expandIcons: "expandIcons", trackBy: "trackBy", totalColumns: "totalColumns", rowClass: "rowClass" }, host: { properties: { "class.k-table-tbody": "this.hostClass" } }, usesOnChanges: true, ngImport: i0, template: `
<tr *ngIf="!hasData" class="k-grid-norecords">
<td [attr.colspan]="colSpan" class="k-table-td">
<ng-container *ngIf="noRecordsTemplate?.templateRef" [ngTemplateOutlet]="noRecordsTemplate.templateRef">
</ng-container>
<ng-container *ngIf="!noRecordsTemplate?.templateRef">
{{noRecordsText}}
</ng-container>
</td>
</tr>
<ng-container *ngFor="let item of view?.data;let rowIndex = index;trackBy: trackByWrapper;">
<tr *ngIf="item.type === 'data'"
kendoTreeListLogicalRow
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)"
[totalColumns]="totalColumns"
[isNew]="item.isNew"
[attr.aria-expanded]="ariaRowExpanded(item)"
[ngClass]="rowClass({ dataItem: item.data, index: $any(item).index })"
class="k-table-row{{isOdd(item) ? ' k-table-alt-row' : ''}}"
[class.k-grid-edit-row]="isEditingRow(item)"
[class.k-grid-add-row]="item.isNew"
[attr.aria-selected]="ariaRowSelected(item)"
[class.k-selected]="item.selected"
[attr.data-treelist-view-index]="rowIndex">
<td kendoTreeListCell
[columnIndex]="lockedColumnsCount + columnIndex"
[column]="column"
[viewItem]="item"
[dataItem]="item.data"
[level]="item.level"
[hasChildren]="item.hasChildren"
[isExpanded]="item.expanded"
[rowIndex]="item.rowIndex"
[loading]="item.loading"
[isNew]="item.isNew"
[selected]="item.selected"
[expandIcons]="expandIcons"
kendoTreeListLogicalCell
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[dataRowIndex]="$any(item).index"
[column]="column"
[colIndex]="columnIndex"
[colSpan]="column.colspan"
[expandable]="cellExpandable(item, column)"
[attr.aria-expanded]="lockedColumnsCount < 1 ? ariaExpanded(item, column) : undefined"
[attr.aria-selected]="lockedColumnsCount < 1 ? ariaSelected(item, column, lockedColumnsCount + columnIndex) : undefined"
class="k-table-td"
[attr.role]="column.tableCellsRole"
[ngClass]="column.cssClass"
[class.k-grid-edit-cell]="isEditingCell(item, column)"
[class.k-selected]="isCellSelected(item.data, column, lockedColumnsCount + columnIndex)"
[ngStyle]="column.style"
[attr.colspan]="column.colspan"
*ngFor="let column of columns; let columnIndex = index; trackBy: trackByColumns;">
</td>
</tr>
<tr *ngIf="item.type === 'footer' && hasFooter" role="row"
class="k-footer"
[attr.data-treelist-view-index]="rowIndex"
kendoTreeListLogicalRow
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)"
[totalColumns]="totalColumns">
<td kendoTreeListLogicalCell
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[column]="column"
[colIndex]="columnIndex"
class="k-table-td"
[attr.role]="column.tableCellsRole"
[ngClass]="column.footerClass"
[ngStyle]="column.footerStyle"
*ngFor="let column of footerColumns; let columnIndex = index; trackBy: trackByColumns;">
<ng-container *ngIf="$any(column).expandable">
<kendo-icon-wrapper name="none" innerCssClass="k-treelist-toggle" [svgIcon]="noneIcon" *ngFor="let item of item.level | levelItems"></kendo-icon-wrapper>
</ng-container>
<ng-container [ngTemplateOutlet]="column.footerTemplateRef"
[ngTemplateOutletContext]="{
$implicit: item.aggregates,
aggregates: item.aggregates,
column: column,
columnIndex: columnIndex,
field: $any(column).field,
items: item.items,
parentItem: item.parentItem
}">
</ng-container>
</td>
</tr>
</ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: LogicalRowDirective, selector: "[kendoTreeListLogicalRow]", inputs: ["logicalRowIndex", "logicalSlaveRow", "logicalCellsCount", "logicalSlaveCellsCount", "dataRowIndex", "dataItem", "isNew", "totalColumns"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CellComponent, selector: "[kendoTreeListCell]", inputs: ["column", "columnIndex", "isNew", "level", "hasChildren", "isExpanded", "loading", "expandIcons", "rowIndex", "selected", "dataItem", "viewItem"] }, { kind: "directive", type: LogicalCellDirective, selector: "[kendoTreeListLogicalCell]", inputs: ["logicalColIndex", "logicalRowIndex", "logicalSlaveCell", "column", "colIndex", "colSpan", "rowSpan", "dataRowIndex", "dataItem", "expandable", "headerLabelText"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "pipe", type: LevelItemsPipe, name: "levelItems" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TableBodyComponent, decorators: [{
type: Component,
args: [{
selector: '[kendoTreeListTableBody]',
template: `
<tr *ngIf="!hasData" class="k-grid-norecords">
<td [attr.colspan]="colSpan" class="k-table-td">
<ng-container *ngIf="noRecordsTemplate?.templateRef" [ngTemplateOutlet]="noRecordsTemplate.templateRef">
</ng-container>
<ng-container *ngIf="!noRecordsTemplate?.templateRef">
{{noRecordsText}}
</ng-container>
</td>
</tr>
<ng-container *ngFor="let item of view?.data;let rowIndex = index;trackBy: trackByWrapper;">
<tr *ngIf="item.type === 'data'"
kendoTreeListLogicalRow
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)"
[totalColumns]="totalColumns"
[isNew]="item.isNew"
[attr.aria-expanded]="ariaRowExpanded(item)"
[ngClass]="rowClass({ dataItem: item.data, index: $any(item).index })"
class="k-table-row{{isOdd(item) ? ' k-table-alt-row' : ''}}"
[class.k-grid-edit-row]="isEditingRow(item)"
[class.k-grid-add-row]="item.isNew"
[attr.aria-selected]="ariaRowSelected(item)"
[class.k-selected]="item.selected"
[attr.data-treelist-view-index]="rowIndex">
<td kendoTreeListCell
[columnIndex]="lockedColumnsCount + columnIndex"
[column]="column"
[viewItem]="item"
[dataItem]="item.data"
[level]="item.level"
[hasChildren]="item.hasChildren"
[isExpanded]="item.expanded"
[rowIndex]="item.rowIndex"
[loading]="item.loading"
[isNew]="item.isNew"
[selected]="item.selected"
[expandIcons]="expandIcons"
kendoTreeListLogicalCell
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[dataRowIndex]="$any(item).index"
[column]="column"
[colIndex]="columnIndex"
[colSpan]="column.colspan"
[expandable]="cellExpandable(item, column)"
[attr.aria-expanded]="lockedColumnsCount < 1 ? ariaExpanded(item, column) : undefined"
[attr.aria-selected]="lockedColumnsCount < 1 ? ariaSelected(item, column, lockedColumnsCount + columnIndex) : undefined"
class="k-table-td"
[attr.role]="column.tableCellsRole"
[ngClass]="column.cssClass"
[class.k-grid-edit-cell]="isEditingCell(item, column)"
[class.k-selected]="isCellSelected(item.data, column, lockedColumnsCount + columnIndex)"
[ngStyle]="column.style"
[attr.colspan]="column.colspan"
*ngFor="let column of columns; let columnIndex = index; trackBy: trackByColumns;">
</td>
</tr>
<tr *ngIf="item.type === 'footer' && hasFooter" role="row"
class="k-footer"
[attr.data-treelist-view-index]="rowIndex"
kendoTreeListLogicalRow
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)"
[totalColumns]="totalColumns">
<td kendoTreeListLogicalCell
[logicalRowIndex]="logicalRowIndex(item.rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[column]="column"
[colIndex]="columnIndex"
class="k-table-td"
[attr.role]="column.tableCellsRole"
[ngClass]="column.footerClass"
[ngStyle]="column.footerStyle"
*ngFor="let column of footerColumns; let columnIndex = index; trackBy: trackByColumns;">
<ng-container *ngIf="$any(column).expandable">
<kendo-icon-wrapper name="none" innerCssClass="k-treelist-toggle" [svgIcon]="noneIcon" *ngFor="let item of item.level | levelItems"></kendo-icon-wrapper>
</ng-container>
<ng-container [ngTemplateOutlet]="column.footerTemplateRef"
[ngTemplateOutletContext]="{
$implicit: item.aggregates,
aggregates: item.aggregates,
column: column,
columnIndex: columnIndex,
field: $any(column).field,
items: item.items,
parentItem: item.parentItem
}">
</ng-container>
</td>
</tr>
</ng-container>
`,
standalone: true,
imports: [NgIf, NgTemplateOutlet, NgFor, LogicalRowDirective, NgClass, CellComponent, LogicalCellDirective, NgStyle, IconWrapperComponent, LevelItemsPipe]
}]
}], ctorParameters: function () { return [{ type: i1.ChangeNotificationService }, { type: i2.EditService }, { type: i3.LocalizationService }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i4.DomEventsService }, { type: i5.ColumnInfoService }, { type: i6.NavigationService }, { type: i7.ExpandStateService }, { type: i8.SelectionService }]; }, propDecorators: { hostClass: [{
type: HostBinding,
args: ['class.k-table-tbody']
}], columns: [{
type: Input
}], allColumns: [{
type: Input
}], noRecordsTemplate: [{
type: Input
}], view: [{
type: Input
}], skip: [{
type: Input
}], filterable: [{
type: Input
}], noRecordsText: [{
type: Input
}], isLocked: [{
type: Input
}], lockedColumnsCount: [{
type: Input
}], totalColumnsCount: [{
type: Input
}], virtualColumns: [{
type: Input
}], expandIcons: [{
type: Input
}], trackBy: [{
type: Input
}], totalColumns: [{
type: Input
}], rowClass: [{
type: Input
}] } });