@progress/kendo-angular-grid
Version:
Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.
997 lines (996 loc) • 49.9 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 { nodesToArray } from './../utils';
import { Component, Input, NgZone, Renderer2, ElementRef, TemplateRef, HostBinding } from '@angular/core';
import { DetailTemplateDirective } from './details/detail-template.directive';
import { GroupsService } from '../grouping/groups.service';
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 { columnsSpan, columnsToRender } from "../columns/column-common";
import { closest, closestInScope, hasClasses, isFocusableWithTabKey, matchesClasses, matchesNodeName } from './common/dom-queries';
import { DomEventsService } from '../common/dom-events.service';
import { SelectionService } from "../selection/selection.service";
import { ColumnInfoService } from "../common/column-info.service";
import { hasFilterRow } from '../filtering/filterable';
import { NavigationService } from '../navigation/navigation.service';
import { isDocumentAvailable, Keys, ResizeSensorComponent, TemplateContextDirective } from '@progress/kendo-angular-common';
import { defaultTrackBy } from '../common/default-track-by';
import { DetailsService } from './details/details.service';
import { NON_DATA_CELL_CLASSES, NON_DATA_ROW_CLASSES, IGNORE_TARGET_CLASSSES, IGNORE_CONTAINER_CLASSES } from './constants';
import { CellSelectionService } from '../selection/cell-selection.service';
import { minusIcon, plusIcon } from '@progress/kendo-svg-icons';
import { ContextService } from '../common/provider.service';
import { ColumnsContainer } from '../columns/columns-container';
import { SpanColumnComponent } from '../columns/span-column.component';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import { GroupHeaderComponent } from '../grouping/group-header.component';
import { CellComponent } from './cell.component';
import { LogicalCellDirective } from '../navigation/logical-cell.directive';
import { LogicalRowDirective } from '../navigation/logical-row.directive';
import { NgIf, NgFor, NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
import { RowspanService } from './rowspan.service';
import * as i0 from "@angular/core";
import * as i1 from "./details/details.service";
import * as i2 from "../grouping/groups.service";
import * as i3 from "../data/change-notification.service";
import * as i4 from "../editing/edit.service";
import * as i5 from "../common/provider.service";
import * as i6 from "../common/dom-events.service";
import * as i7 from "../selection/selection.service";
import * as i8 from "../selection/cell-selection.service";
import * as i9 from "../common/column-info.service";
import * as i10 from "../navigation/navigation.service";
import * as i11 from "./rowspan.service";
const columnCellIndex = (cell, cells) => {
let cellIndex = 0;
for (let idx = 0; idx < cells.length; idx++) {
if (cells[idx] === cell) {
return cellIndex;
}
if (!hasClasses(cells[idx], 'k-hierarchy-cell k-group-cell')) {
cellIndex++;
}
}
};
/**
* @hidden
*/
export class TableBodyComponent {
detailsService;
groupsService;
changeNotification;
editService;
ctx;
ngZone;
renderer;
element;
domEvents;
selectionService;
cellSelectionService;
columnInfoService;
navigationService;
rowspanService;
columns = [];
allColumns;
groups = [];
detailTemplate;
noRecordsTemplate;
data;
skip = 0;
selectable;
filterable;
noRecordsText;
isLocked = false;
isLoading;
isVirtual;
cellLoadingTemplate;
skipGroupDecoration = false;
showGroupFooters = false;
lockedColumnsCount = 0;
totalColumnsCount = 0;
virtualColumns;
trackBy = defaultTrackBy;
rowSticky;
totalColumns;
rowClass = () => null;
hostClass = true;
groupHeaderSlaveCellsCount;
groupHeaderColumns;
clickSubscription;
touchSubscription;
l10nSubscription;
cellKeydownSubscription;
clickTimeout;
minusIcon = minusIcon;
plusIcon = plusIcon;
dataArray;
rerender = false;
constructor(detailsService, groupsService, changeNotification, editService, ctx, ngZone, renderer, element, domEvents, selectionService, cellSelectionService, columnInfoService, navigationService, rowspanService) {
this.detailsService = detailsService;
this.groupsService = groupsService;
this.changeNotification = changeNotification;
this.editService = editService;
this.ctx = ctx;
this.ngZone = ngZone;
this.renderer = renderer;
this.element = element;
this.domEvents = domEvents;
this.selectionService = selectionService;
this.cellSelectionService = cellSelectionService;
this.columnInfoService = columnInfoService;
this.navigationService = navigationService;
this.rowspanService = rowspanService;
this.noRecordsText = this.ctx.localization.get('noRecords');
this.cellKeydownSubscription = this.navigationService.cellKeydown.subscribe((args) => this.cellKeydownHandler(args));
this.trackByWrapper = this.trackByWrapper.bind(this);
this.trackByColumns = this.trackByColumns.bind(this);
}
get newDataItem() {
return this.editService.newDataItem;
}
get cachedDataArray() {
if (!this.dataArray) {
this.dataArray = this.data.map(item => item);
}
return this.dataArray;
}
// 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 - allColumns.length;
return item && this.isDataItem(item) ? contentColumnsCount : headerFooterColumnsCount;
}
shouldSkipCell(rowIndex, colIndex) {
return this.rowspanService.shouldSkip(rowIndex, colIndex);
}
getRowspan(row, column, colIndex) {
if (this.rerender) {
this.dataArray = null;
this.rerender = false;
}
const rowspan = column.cellRowspan(row, column, this.cachedDataArray);
if (rowspan > 1) {
this.rowspanService.addCells(row.index, colIndex, rowspan);
}
this.ngZone.runOutsideAngular(() => setTimeout(() => {
this.rerender = true;
this.rowspanService.reset();
}));
return rowspan;
}
isAriaSelected(item, column) {
return this.cellSelectionService.isCellSelected(item, column) ||
this.isRowSelected(item) ? 'true' : 'false';
}
toggleRow(index, dataItem) {
this.detailsService.toggleRow(index, dataItem);
return false;
}
isExpanded(viewItem) {
return this.detailsService.isExpanded(viewItem.index, viewItem.data);
}
detailButtonIconName(viewItem) {
const expanded = this.isExpanded(viewItem);
return expanded ? 'minus' : 'plus';
}
detailButtonSvgIcon(viewItem) {
const expanded = this.isExpanded(viewItem);
return expanded ? this.minusIcon : this.plusIcon;
}
detailButtonTitle(viewItem) {
const messageKey = this.isExpanded(viewItem) ? 'detailCollapse' : 'detailExpand';
return this.ctx.localization.get(messageKey);
}
isGroup(item) {
return item.type === 'group';
}
isDataItem(item) {
return !this.isGroup(item) && !this.isFooter(item);
}
isFooter(item) {
return item.type === 'footer';
}
isFooterItemInExpandedGroup(item) {
const footerItem = { data: item.data, index: item.groupIndex, parentGroup: item.group.parentGroup };
return this.isInExpandedGroup(footerItem);
}
isDataItemInExpandedGroup(item) {
const dataItem = { data: item.group.data, index: item.groupIndex, parentGroup: item.group.parentGroup };
return this.isInExpandedGroup(dataItem);
}
isInExpandedGroup(item) {
return this.groupsService.isInExpandedGroup(item);
}
isParentGroupExpanded(item) {
return this.groupsService.isInExpandedGroup(item.parentGroup);
}
isOdd(item) {
return item.index % 2 !== 0;
}
isSelectable(args) {
const rowSelectable = this.isRowSelectable(args);
const selectionEnabled = this.selectable && this.selectable.enabled !== false;
return selectionEnabled && rowSelectable;
}
isRowSelected(item) {
return this.selectionService.isSelected(item.index);
}
isRowSelectable(args) {
return this.selectionService.settings?.isRowSelectable(args) || this.cellSelectionService.settings?.isRowSelectable(args);
}
trackByWrapper(index, item) {
if (item.type === 'data') {
item.isEditing = this.editService.hasEdited(item.index);
}
return this.trackBy(index, item);
}
trackByColumns(index, item) {
return this.virtualColumns ? index : item;
}
ngDoCheck() {
if (this.hasGroupHeaderColumn) {
this.groupHeaderColumns = columnsToRender(this.skipGroupDecoration ? this.columns : this.columns.toArray().slice(1));
}
else {
this.groupHeaderColumns = [];
}
if (this.isLocked) {
this.groupHeaderSlaveCellsCount =
this.hasGroupHeaderColumn ? this.columnsContainer.nonLockedColumnsToRender.length : 1;
}
else {
this.groupHeaderSlaveCellsCount = 0;
}
}
ngAfterViewChecked() {
if (this.rowSticky) {
this.applyStickyRowsStyling();
}
}
ngOnChanges(changes) {
if (isChanged('columns', changes, false)) {
this.changeNotification.notify();
}
}
logicalRowIndex(rowIndex) {
let pos = this.skip + rowIndex;
if (this.hasDetailTemplate) {
pos *= 2;
}
const absoluteRowIndex = 1 + pos;
const addRowOffset = this.editService.hasNewItem ? 1 : 0;
const filterRowOffset = hasFilterRow(this.filterable) ? 1 : 0;
const headerRowCount = this.columnInfoService.totalLevels + filterRowOffset + addRowOffset;
return absoluteRowIndex + headerRowCount;
}
addRowLogicalIndex() {
return this.columnInfoService.totalLevels + 1 +
(hasFilterRow(this.filterable) ? 1 : 0);
}
logicalColIndex(column) {
if (!isPresent(column.leafIndex)) {
return -1;
}
return column.leafIndex + (this.hasDetailTemplate ? 1 : 0);
}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
const clickHandler = this.clickHandler.bind(this);
const mousedownSubscription = this.renderer.listen(this.element.nativeElement, 'mousedown', clickHandler);
const mouseupSubscription = this.renderer.listen(this.element.nativeElement, 'mouseup', clickHandler);
const clickSubscription = this.renderer.listen(this.element.nativeElement, 'click', clickHandler);
const contextmenuSubscription = this.renderer.listen(this.element.nativeElement, 'contextmenu', clickHandler);
const touchstartSubscription = this.renderer.listen(this.element.nativeElement, 'touchstart', clickHandler);
const touchendSubscription = this.renderer.listen(this.element.nativeElement, 'touchend', clickHandler);
this.clickSubscription = () => {
mousedownSubscription();
mouseupSubscription();
clickSubscription();
contextmenuSubscription();
};
this.touchSubscription = () => {
touchstartSubscription();
touchendSubscription();
};
});
let originalNoRecordText = this.ctx.localization.get('noRecords');
this.l10nSubscription = this.ctx.localization.changes.subscribe(() => {
if (this.noRecordsText === originalNoRecordText) {
this.noRecordsText = this.ctx.localization.get('noRecords');
originalNoRecordText = this.noRecordsText;
}
});
}
ngOnDestroy() {
if (this.clickSubscription) {
this.clickSubscription();
}
if (this.touchSubscription) {
this.touchSubscription();
}
if (this.l10nSubscription) {
this.l10nSubscription.unsubscribe();
}
this.cellKeydownSubscription.unsubscribe();
clearTimeout(this.clickTimeout);
}
isEditingCell(index, column) {
return this.editService.isEditing() && this.editService.isEditedColumn(index, column);
}
isEditingRow(index) {
return this.editService.isEditing() && this.editService.hasEdited(index);
}
get hasGroupHeaderColumn() {
return this.columnsContainer.hasGroupHeaderColumn;
}
get columnsContainer() {
return this.columnInfoService.columnsContainer;
}
get columnsSpan() {
return columnsSpan(this.columns);
}
get allColumnsSpan() {
return columnsSpan(this.allColumns || this.columns);
}
get colSpan() {
return this.columnsSpan + this.groups.length + (this.hasDetailTemplate ? 1 : 0);
}
get footerColumns() {
const colsToRender = Array.from(this.columns).reduce((cols, col) => {
const newCols = (col instanceof SpanColumnComponent) ? Array.from(col.childColumns) : [col];
return [...cols, ...newCols];
}, []);
return colsToRender;
}
showGroupHeader(item) {
return !item.data.skipHeader;
}
addStickyColumnStyles(column) {
const stickyStyles = this.columnInfoService.stickyColumnsStyles(column);
return { ...column.style, ...stickyStyles };
}
resizeHandler() {
this.applyStickyRowsStyling();
}
get hasDetailTemplate() {
return isPresent(this.detailTemplate);
}
clickHandler(eventArg) {
const element = this.element.nativeElement;
const target = this.eventTarget(eventArg);
let cell, row, body, gridElement;
let currentTarget = target;
do {
cell = closest(currentTarget, matchesNodeName('td'));
row = closest(cell, matchesNodeName('tr'));
body = closest(row, matchesNodeName('tbody'));
currentTarget = body;
gridElement = closestInScope(currentTarget, matchesClasses('k-grid'), element);
} while (body && body !== element && !gridElement);
if (cell && !hasClasses(cell, NON_DATA_CELL_CLASSES) &&
!hasClasses(row, NON_DATA_ROW_CLASSES) &&
body === element && !gridElement) {
this.editService.preventCellClose();
const focusable = target !== cell && isFocusableWithTabKey(target, false);
if (!focusable && !matchesNodeName('label')(target) && !hasClasses(target, IGNORE_TARGET_CLASSSES) &&
!closestInScope(target, matchesClasses(IGNORE_CONTAINER_CLASSES), cell)) {
const args = this.cellClickArgs(cell, row, eventArg);
const selectionEnabled = this.selectable && this.selectable.enabled !== false;
if (selectionEnabled && !this.isRowSelectable({ index: args.rowIndex, dataItem: args.dataItem })) {
return;
}
if (eventArg.type === 'mousedown' || eventArg.type === 'touchstart') {
this.domEvents.cellMousedown.emit(args);
}
else if (eventArg.type === 'mouseup' || eventArg.type === 'touchend') {
this.domEvents.cellMouseup.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(Object.assign(args, {
isEdited: args.isEditedRow || args.isEditedColumn
}));
}
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;
let rowIndex = row.getAttribute('data-kendo-grid-item-index');
rowIndex = rowIndex ? parseInt(rowIndex, 10) : -1;
const dataItem = rowIndex === -1 ? this.editService.newDataItem : this.data.at(rowIndex - this.skip);
const isEditedColumn = this.editService.isEditedColumn(rowIndex, column);
const isEditedRow = this.editService.isEdited(rowIndex);
const type = eventArg.type === 'keydown' ? 'click' : eventArg.type;
return {
column: column,
columnIndex: columnIndex,
dataItem: dataItem,
isEditedColumn: isEditedColumn,
isEditedRow: isEditedRow,
originalEvent: eventArg,
rowIndex: rowIndex,
type: type
};
}
eventTarget(args) {
if (!isDocumentAvailable()) {
return;
}
if (args.type === 'touchend') {
const touch = args.changedTouches[0];
return document.elementFromPoint(touch.clientX, touch.clientY);
}
return args.target;
}
applyStickyRowsStyling() {
if (!isDocumentAvailable()) {
return;
}
const stickyRows = nodesToArray(this.element.nativeElement.querySelectorAll('.k-grid-row-sticky'));
const length = stickyRows.length;
if (length) {
let accumulatedHeight = 0;
const stickyRowsOffsets = [];
stickyRows.forEach(row => {
const rowHeight = row.getBoundingClientRect().height;
stickyRowsOffsets.push({ accumulatedHeight, rowHeight });
accumulatedHeight += rowHeight;
});
stickyRows.forEach((row, index) => {
this.renderer.setStyle(row, 'top', `${stickyRowsOffsets[index].accumulatedHeight}px`);
this.renderer.setStyle(row, 'bottom', `${accumulatedHeight - stickyRowsOffsets[index].accumulatedHeight - stickyRowsOffsets[index].rowHeight}px`);
});
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TableBodyComponent, deps: [{ token: i1.DetailsService }, { token: i2.GroupsService }, { token: i3.ChangeNotificationService }, { token: i4.EditService }, { token: i5.ContextService }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i6.DomEventsService }, { token: i7.SelectionService }, { token: i8.CellSelectionService }, { token: i9.ColumnInfoService }, { token: i10.NavigationService }, { token: i11.RowspanService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TableBodyComponent, isStandalone: true, selector: "[kendoGridTableBody]", inputs: { columns: "columns", allColumns: "allColumns", groups: "groups", detailTemplate: "detailTemplate", noRecordsTemplate: "noRecordsTemplate", data: "data", skip: "skip", selectable: "selectable", filterable: "filterable", noRecordsText: "noRecordsText", isLocked: "isLocked", isLoading: "isLoading", isVirtual: "isVirtual", cellLoadingTemplate: "cellLoadingTemplate", skipGroupDecoration: "skipGroupDecoration", showGroupFooters: "showGroupFooters", lockedColumnsCount: "lockedColumnsCount", totalColumnsCount: "totalColumnsCount", virtualColumns: "virtualColumns", trackBy: "trackBy", rowSticky: "rowSticky", totalColumns: "totalColumns", rowClass: "rowClass" }, host: { properties: { "class.k-table-tbody": "this.hostClass" } }, usesOnChanges: true, ngImport: i0, template: `
<ng-container *ngIf="editService.hasNewItem">
<tr class="k-grid-add-row k-grid-edit-row k-master-row"
kendoGridLogicalRow
[logicalRowIndex]="addRowLogicalIndex()"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount()"
[totalColumns]="totalColumns">
<ng-container *ngIf="!skipGroupDecoration">
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups" role="presentation"></td>
</ng-container>
<td class="k-hierarchy-cell k-table-td"
*ngIf="detailTemplate?.templateRef"
kendoGridLogicalCell
[logicalRowIndex]="addRowLogicalIndex()"
[logicalColIndex]="0"
aria-selected="false"
>
</td>
<td *ngFor="let column of columns; let columnIndex = index; trackBy: trackByColumns;"
class="k-table-td"
kendoGridCell
[rowIndex]="-1"
[columnIndex]="lockedColumnsCount + columnIndex"
[isNew]="true"
[column]="column"
[dataItem]="newDataItem"
[class.k-grid-content-sticky]="column.sticky"
[ngClass]="column.cssClass"
[style.left]="column.sticky ? '0' : undefined"
[ngStyle]="column.sticky ? addStickyColumnStyles(column) : column.style"
[attr.colspan]="column.colspan"
[attr.role]="column.tableCellsRole"
kendoGridLogicalCell
[logicalRowIndex]="addRowLogicalIndex()"
[logicalColIndex]="logicalColIndex(column)"
[colSpan]="column.colspan">
</td>
</tr>
</ng-container>
<tr *ngIf="data?.length === 0 || data === null" class="k-grid-norecords" role="row">
<td [attr.colspan]="colSpan" class="k-table-td">
<ng-template
*ngIf="noRecordsTemplate?.templateRef"
[templateContext]="{
templateRef: noRecordsTemplate?.templateRef
}">
</ng-template>
<ng-container *ngIf="!noRecordsTemplate?.templateRef">
{{noRecordsText}}
</ng-container>
</td>
</tr>
<ng-container *ngFor="let item of data; trackBy: trackByWrapper; let rowIndex = index;">
<tr *ngIf="isGroup(item) && isParentGroupExpanded($any(item)) && showGroupHeader(item)"
kendoGridGroupHeader
[columns]="columns"
[groups]="groups"
[item]="$any(item)"
[hasDetails]="!!detailTemplate?.templateRef"
[skipGroupDecoration]="skipGroupDecoration"
[hasGroupHeaderColumn]="hasGroupHeaderColumn"
[groupHeaderColumns]="groupHeaderColumns"
[rowIndex]="rowIndex + 1"
[totalColumnsCount]="totalColumnsCount"
kendoGridLogicalRow
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[totalColumns]="totalColumns"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="groupHeaderSlaveCellsCount">
</tr>
<tr
*ngIf="isDataItem(item) && (!$any(item).group || isDataItemInExpandedGroup($any(item)))"
kendoGridLogicalRow
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[totalColumns]="totalColumns"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)"
class="{{ isOdd(item) ? 'k-table-alt-row' : ''}}"
[class.k-grid-row-sticky]="rowSticky ? rowSticky({ dataItem: item.data, index: $any(item).index }) : false"
[ngClass]="rowClass({ dataItem: item.data, index: $any(item).index })"
[class.k-master-row]="true"
[class.k-expanded]="isDataItem(item) && isExpanded(item)"
[class.k-grid-edit-row]="isEditingRow($any(item).index)"
[attr.aria-selected]="lockedColumnsCount < 1 ? isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item) : undefined"
[attr.data-kendo-grid-item-index]="$any(item).index"
[class.k-selected]="isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item)">
<ng-container *ngIf="!skipGroupDecoration">
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups" role="presentation"></td>
</ng-container>
<td class="k-hierarchy-cell k-table-td"
*ngIf="detailTemplate?.templateRef"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="0"
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[detailExpandCell]="true"
aria-selected="false"
role="gridcell">
<a
*ngIf="detailTemplate.showIf(item.data, $any(item).index)"
[attr.title]="detailButtonTitle(item)"
[attr.aria-label]="detailButtonTitle(item)"
href="#" tabindex="-1" (click)="toggleRow($any(item).index, item.data)">
<kendo-icon-wrapper
[name]="detailButtonIconName(item)"
[svgIcon]="detailButtonSvgIcon(item)"></kendo-icon-wrapper>
</a>
</td>
<ng-container *ngFor="let column of columns; let columnIndex = index; trackBy: trackByColumns;">
<td *ngIf="column.cellRowspan ? !shouldSkipCell(rowIndex, lockedColumnsCount + columnIndex) : true"
kendoGridCell
[rowIndex]="$any(item).index"
[columnIndex]="lockedColumnsCount + columnIndex"
[attr.data-kendo-grid-column-index]="lockedColumnsCount + columnIndex"
[column]="column"
[dataItem]="item.data"
[isLoading]="isLoading"
[isVirtual]="isVirtual"
[loadingTemplate]="cellLoadingTemplate"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[colIndex]="columnIndex"
[colSpan]="column.colspan"
[rowSpan]="column.cellRowspan ? getRowspan({
index: rowIndex,
dataItem: item
}, column, lockedColumnsCount + columnIndex) : 1"
[attr.role]="column.tableCellsRole"
class="k-table-td"
[attr.aria-selected]="lockedColumnsCount < 1 && isSelectable({ dataItem: item.data, index: $any(item).index }) ? isAriaSelected(item, column) : undefined"
[class.k-grid-content-sticky]="column.sticky"
[class.k-touch-action-none]="isSelectable({ dataItem: item.data, index: $any(item).index }) && $any(selectable).drag"
[ngClass]="column.cssClass"
[class.k-grid-edit-cell]="isEditingCell($any(item).index, column)"
[ngStyle]="column.sticky ? addStickyColumnStyles(column) : column.style"
[attr.colspan]="column.colspan"
[class.k-selected]="isSelectable && cellSelectionService.isCellSelected(item, column)"
>
</td>
</ng-container>
</tr>
<tr *ngIf="isDataItem(item) &&
(!$any(item).group || isDataItemInExpandedGroup($any(item))) &&
detailTemplate?.templateRef &&
detailTemplate.showIf(item.data, $any(item).index) &&
isExpanded(item)"
class="k-detail-row"
kendoGridLogicalRow
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[logicalRowIndex]="logicalRowIndex(rowIndex) + 1"
[logicalSlaveRow]="false"
[logicalCellsCount]="1"
>
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups"></td>
<td class="k-hierarchy-cell k-table-td"></td>
<td class="k-detail-cell k-table-td"
[attr.colspan]="columnsSpan"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex) + 1"
[logicalColIndex]="0"
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[colIndex]="0"
[colSpan]="allColumnsSpan + 1"
role="gridcell" aria-selected="false"
>
<ng-template
[ngTemplateOutlet]="detailTemplate.templateRef"
[ngTemplateOutletContext]="{
dataItem: item.data,
rowIndex: $any(item).index,
$implicit: item.data
}">
</ng-template>
</td>
</tr>
<tr *ngIf="isFooter(item) &&
$any(item).group &&
(isFooterItemInExpandedGroup($any(item)) || (showGroupFooters && isParentGroupExpanded($any(item).group))) &&
!$any(item.data).hideFooter"
class="k-group-footer"
kendoGridLogicalRow
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[totalColumns]="totalColumns"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)">
<ng-container *ngIf="!skipGroupDecoration">
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups"></td>
</ng-container>
<td class="k-hierarchy-cell k-table-td"
*ngIf="detailTemplate?.templateRef"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="0"
aria-selected="false"
>
</td>
<td kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[attr.data-skip]="skipGroupDecoration"
class="k-table-td"
*ngFor="let column of footerColumns; let columnIndex = index; trackBy: trackByColumns;">
<ng-template
[templateContext]="{
templateRef: $any(column).groupFooterTemplateRef,
group: $any(item.data),
field: $any(column).field,
column: column,
aggregates: $any(item.data)?.aggregates,
$implicit: $any(item.data)?.aggregates
}">
</ng-template>
</td>
</tr>
</ng-container>
<kendo-resize-sensor *ngIf="rowSticky" (resize)="resizeHandler()"></kendo-resize-sensor>
`, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: LogicalRowDirective, selector: "[kendoGridLogicalRow]", inputs: ["logicalRowIndex", "logicalSlaveRow", "logicalCellsCount", "logicalSlaveCellsCount", "dataRowIndex", "dataItem", "totalColumns"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: LogicalCellDirective, selector: "[kendoGridLogicalCell]", inputs: ["logicalColIndex", "logicalRowIndex", "logicalSlaveCell", "colIndex", "colSpan", "rowSpan", "groupItem", "dataRowIndex", "dataItem", "detailExpandCell", "headerLabelText"] }, { kind: "component", type: CellComponent, selector: "[kendoGridCell]", inputs: ["column", "columnIndex", "isNew", "isLoading", "isVirtual", "loadingTemplate", "rowIndex", "dataItem"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { kind: "component", type: GroupHeaderComponent, selector: "[kendoGridGroupHeader]", inputs: ["rowIndex", "logicalRowIndex", "item", "skipGroupDecoration", "hasDetails", "totalColumnsCount", "hasGroupHeaderColumn", "groupHeaderColumns", "columns", "groups"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TableBodyComponent, decorators: [{
type: Component,
args: [{
selector: '[kendoGridTableBody]',
template: `
<ng-container *ngIf="editService.hasNewItem">
<tr class="k-grid-add-row k-grid-edit-row k-master-row"
kendoGridLogicalRow
[logicalRowIndex]="addRowLogicalIndex()"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount()"
[totalColumns]="totalColumns">
<ng-container *ngIf="!skipGroupDecoration">
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups" role="presentation"></td>
</ng-container>
<td class="k-hierarchy-cell k-table-td"
*ngIf="detailTemplate?.templateRef"
kendoGridLogicalCell
[logicalRowIndex]="addRowLogicalIndex()"
[logicalColIndex]="0"
aria-selected="false"
>
</td>
<td *ngFor="let column of columns; let columnIndex = index; trackBy: trackByColumns;"
class="k-table-td"
kendoGridCell
[rowIndex]="-1"
[columnIndex]="lockedColumnsCount + columnIndex"
[isNew]="true"
[column]="column"
[dataItem]="newDataItem"
[class.k-grid-content-sticky]="column.sticky"
[ngClass]="column.cssClass"
[style.left]="column.sticky ? '0' : undefined"
[ngStyle]="column.sticky ? addStickyColumnStyles(column) : column.style"
[attr.colspan]="column.colspan"
[attr.role]="column.tableCellsRole"
kendoGridLogicalCell
[logicalRowIndex]="addRowLogicalIndex()"
[logicalColIndex]="logicalColIndex(column)"
[colSpan]="column.colspan">
</td>
</tr>
</ng-container>
<tr *ngIf="data?.length === 0 || data === null" class="k-grid-norecords" role="row">
<td [attr.colspan]="colSpan" class="k-table-td">
<ng-template
*ngIf="noRecordsTemplate?.templateRef"
[templateContext]="{
templateRef: noRecordsTemplate?.templateRef
}">
</ng-template>
<ng-container *ngIf="!noRecordsTemplate?.templateRef">
{{noRecordsText}}
</ng-container>
</td>
</tr>
<ng-container *ngFor="let item of data; trackBy: trackByWrapper; let rowIndex = index;">
<tr *ngIf="isGroup(item) && isParentGroupExpanded($any(item)) && showGroupHeader(item)"
kendoGridGroupHeader
[columns]="columns"
[groups]="groups"
[item]="$any(item)"
[hasDetails]="!!detailTemplate?.templateRef"
[skipGroupDecoration]="skipGroupDecoration"
[hasGroupHeaderColumn]="hasGroupHeaderColumn"
[groupHeaderColumns]="groupHeaderColumns"
[rowIndex]="rowIndex + 1"
[totalColumnsCount]="totalColumnsCount"
kendoGridLogicalRow
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[totalColumns]="totalColumns"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="groupHeaderSlaveCellsCount">
</tr>
<tr
*ngIf="isDataItem(item) && (!$any(item).group || isDataItemInExpandedGroup($any(item)))"
kendoGridLogicalRow
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[totalColumns]="totalColumns"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)"
class="{{ isOdd(item) ? 'k-table-alt-row' : ''}}"
[class.k-grid-row-sticky]="rowSticky ? rowSticky({ dataItem: item.data, index: $any(item).index }) : false"
[ngClass]="rowClass({ dataItem: item.data, index: $any(item).index })"
[class.k-master-row]="true"
[class.k-expanded]="isDataItem(item) && isExpanded(item)"
[class.k-grid-edit-row]="isEditingRow($any(item).index)"
[attr.aria-selected]="lockedColumnsCount < 1 ? isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item) : undefined"
[attr.data-kendo-grid-item-index]="$any(item).index"
[class.k-selected]="isSelectable({ dataItem: item.data, index: $any(item).index }) && isRowSelected(item)">
<ng-container *ngIf="!skipGroupDecoration">
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups" role="presentation"></td>
</ng-container>
<td class="k-hierarchy-cell k-table-td"
*ngIf="detailTemplate?.templateRef"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="0"
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[detailExpandCell]="true"
aria-selected="false"
role="gridcell">
<a
*ngIf="detailTemplate.showIf(item.data, $any(item).index)"
[attr.title]="detailButtonTitle(item)"
[attr.aria-label]="detailButtonTitle(item)"
href="#" tabindex="-1" (click)="toggleRow($any(item).index, item.data)">
<kendo-icon-wrapper
[name]="detailButtonIconName(item)"
[svgIcon]="detailButtonSvgIcon(item)"></kendo-icon-wrapper>
</a>
</td>
<ng-container *ngFor="let column of columns; let columnIndex = index; trackBy: trackByColumns;">
<td *ngIf="column.cellRowspan ? !shouldSkipCell(rowIndex, lockedColumnsCount + columnIndex) : true"
kendoGridCell
[rowIndex]="$any(item).index"
[columnIndex]="lockedColumnsCount + columnIndex"
[attr.data-kendo-grid-column-index]="lockedColumnsCount + columnIndex"
[column]="column"
[dataItem]="item.data"
[isLoading]="isLoading"
[isVirtual]="isVirtual"
[loadingTemplate]="cellLoadingTemplate"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[colIndex]="columnIndex"
[colSpan]="column.colspan"
[rowSpan]="column.cellRowspan ? getRowspan({
index: rowIndex,
dataItem: item
}, column, lockedColumnsCount + columnIndex) : 1"
[attr.role]="column.tableCellsRole"
class="k-table-td"
[attr.aria-selected]="lockedColumnsCount < 1 && isSelectable({ dataItem: item.data, index: $any(item).index }) ? isAriaSelected(item, column) : undefined"
[class.k-grid-content-sticky]="column.sticky"
[class.k-touch-action-none]="isSelectable({ dataItem: item.data, index: $any(item).index }) && $any(selectable).drag"
[ngClass]="column.cssClass"
[class.k-grid-edit-cell]="isEditingCell($any(item).index, column)"
[ngStyle]="column.sticky ? addStickyColumnStyles(column) : column.style"
[attr.colspan]="column.colspan"
[class.k-selected]="isSelectable && cellSelectionService.isCellSelected(item, column)"
>
</td>
</ng-container>
</tr>
<tr *ngIf="isDataItem(item) &&
(!$any(item).group || isDataItemInExpandedGroup($any(item))) &&
detailTemplate?.templateRef &&
detailTemplate.showIf(item.data, $any(item).index) &&
isExpanded(item)"
class="k-detail-row"
kendoGridLogicalRow
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[logicalRowIndex]="logicalRowIndex(rowIndex) + 1"
[logicalSlaveRow]="false"
[logicalCellsCount]="1"
>
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups"></td>
<td class="k-hierarchy-cell k-table-td"></td>
<td class="k-detail-cell k-table-td"
[attr.colspan]="columnsSpan"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex) + 1"
[logicalColIndex]="0"
[dataRowIndex]="$any(item).index"
[dataItem]="item.data"
[colIndex]="0"
[colSpan]="allColumnsSpan + 1"
role="gridcell" aria-selected="false"
>
<ng-template
[ngTemplateOutlet]="detailTemplate.templateRef"
[ngTemplateOutletContext]="{
dataItem: item.data,
rowIndex: $any(item).index,
$implicit: item.data
}">
</ng-template>
</td>
</tr>
<tr *ngIf="isFooter(item) &&
$any(item).group &&
(isFooterItemInExpandedGroup($any(item)) || (showGroupFooters && isParentGroupExpanded($any(item).group))) &&
!$any(item.data).hideFooter"
class="k-group-footer"
kendoGridLogicalRow
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalSlaveRow]="lockedColumnsCount > 0"
[totalColumns]="totalColumns"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount(item)">
<ng-container *ngIf="!skipGroupDecoration">
<td class="k-group-cell k-table-td k-table-group-td" *ngFor="let g of groups"></td>
</ng-container>
<td class="k-hierarchy-cell k-table-td"
*ngIf="detailTemplate?.templateRef"
kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="0"
aria-selected="false"
>
</td>
<td kendoGridLogicalCell
[logicalRowIndex]="logicalRowIndex(rowIndex)"
[logicalColIndex]="logicalColIndex(column)"
[attr.data-skip]="skipGroupDecoration"
class="k-table-td"
*ngFor="let column of footerColumns; let columnIndex = index; trackBy: trackByColumns;">
<ng-template
[templateContext]="{
templateRef: $any(column).groupFooterTemplateRef,
group: $any(item.data),
field: $any(column).field,
column: column,
aggregates: $any(item.data)?.aggregates,
$implicit: $any(item.data)?.aggregates
}">
</ng-template>
</td>
</tr>
</ng-container>
<kendo-resize-sensor *ngIf="rowSticky" (resize)="resizeHandler()"></kendo-resize-sensor>
`,
standalone: true,
imports: [
NgIf, LogicalRowDirective, NgFor, LogicalCellDirective, CellComponent, NgClass, NgStyle, TemplateContextDirective,
GroupHeaderComponent, IconWrapperComponent, NgTemplateOutlet, ResizeSensorComponent
]
}]
}], ctorParameters: function () { return [{ type: i1.DetailsService }, { type: i2.GroupsService }, { type: i3.ChangeNotificationService }, { type: i4.EditService }, { type: i5.ContextService }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i6.DomEventsService }, { type: i7.SelectionService }, { type: i8.CellSelectionService }, { type: i9.ColumnInfoService }, { type: i10.NavigationService }, { type: i11.RowspanService }]; }, propDecorators: { columns: [{
type: Input
}], allColumns: [{
type: Input
}], groups: [{
type: Input
}], detailTemplate: [{
type: Input
}], noRecordsTemplate: [{
type: Input
}], data: [{
type: Input
}], skip: [{
type: Input
}], selectable: [{
type: Input
}], filterable: [{
type: Input
}], noRecordsText: [{
type: Input
}], isLocked: [{
type: Input
}], isLoading: [{
type: Input
}], isVirtual: [{
type: Input
}], cellLoadingTemplate: [{
type: Input
}], skipGroupDecoration: [{
type: Input
}], showGroupFooters: [{
type: Input
}], lockedColumnsCount: [{
type: Input
}], totalColumnsCount: [{
type: Input
}], virtualColumns: [{
type: Input
}], trackBy: [{
type: Input
}], rowSticky: [{
type: Input
}], totalColumns: [{
type: Input
}], rowClass: [{
type: Input
}], hostClass: [{
type: HostBinding,
args: ['class.k-table-tbody']
}] } });