UNPKG

@siemens/ngx-datatable

Version:

ngx-datatable is an Angular table grid component for presenting large and complex data.

1,150 lines (1,144 loc) 113 kB
import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, Output, ViewChild } from '@angular/core'; import { ScrollerComponent } from './scroller.component'; import { columnGroupWidths, columnsByPin } from '../../utils/column'; import { RowHeightCache } from '../../utils/row-height-cache'; import { translateXY } from '../../utils/translate'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "../../directives/draggable.directive"; import * as i3 from "./scroller.component"; import * as i4 from "./progress-bar.component"; import * as i5 from "./body-row.component"; import * as i6 from "./body-row-wrapper.component"; import * as i7 from "./selection.component"; import * as i8 from "./summary/summary-row.component"; import * as i9 from "./ghost-loader/ghost-loader.component"; import * as i10 from "./body-row-def.component"; export class DataTableBodyComponent { set ghostLoadingIndicator(val) { this._ghostLoadingIndicator = val; if (!val) { // remove placeholder rows once ghostloading is set to false this.temp = this.temp.filter(item => !!item); } } ; get ghostLoadingIndicator() { return this._ghostLoadingIndicator; } set pageSize(val) { if (val !== this._pageSize) { this._pageSize = val; this.recalcLayout(); // Emits the page event if page size has been changed this._offsetEvent = -1; this.updatePage('up'); this.updatePage('down'); } } get pageSize() { return this._pageSize; } set rows(val) { if (val !== this._rows) { this._rows = val; this.recalcLayout(); } } get rows() { return this._rows; } set columns(val) { if (val !== this._columns) { this._columns = val; const colsByPin = columnsByPin(val); this.columnGroupWidths = columnGroupWidths(colsByPin, val); } } get columns() { return this._columns; } set offset(val) { if (val !== this._offset) { this._offset = val; if (!this.scrollbarV || (this.scrollbarV && !this.virtualization)) { if (!isNaN(this._offset) && this.ghostLoadingIndicator) { this.rows = []; } this.recalcLayout(); } } } get offset() { return this._offset; } set rowCount(val) { if (val !== this._rowCount) { this._rowCount = val; this.recalcLayout(); } } get rowCount() { return this._rowCount; } get bodyWidth() { if (this.scrollbarH) { return this.innerWidth + 'px'; } else { return '100%'; } } set bodyHeight(val) { if (this.scrollbarV) { this._bodyHeight = val + 'px'; } else { this._bodyHeight = 'auto'; } this.recalcLayout(); } get bodyHeight() { return this._bodyHeight; } /** * Returns if selection is enabled. */ get selectEnabled() { return !!this.selectionType; } /** * Property that would calculate the height of scroll bar * based on the row heights cache for virtual scroll and virtualization. Other scenarios * calculate scroll height automatically (as height will be undefined). */ get scrollHeight() { if (this.scrollbarV && this.virtualization && this.rowCount) { return this.rowHeightsCache.query(this.rowCount - 1); } // avoid TS7030: Not all code paths return a value. return undefined; } /** * Creates an instance of DataTableBodyComponent. */ constructor(cd) { this.cd = cd; this.selected = []; this.verticalScrollVisible = false; this.scroll = new EventEmitter(); this.page = new EventEmitter(); this.activate = new EventEmitter(); this.select = new EventEmitter(); this.detailToggle = new EventEmitter(); this.rowContextmenu = new EventEmitter(false); this.treeAction = new EventEmitter(); this.rowHeightsCache = new RowHeightCache(); this.temp = []; this.offsetY = 0; this.indexes = {}; this.rowIndexes = new WeakMap(); this.rowExpansions = []; this._offsetEvent = -1; /** * Get the height of the detail row. */ this.getDetailRowHeight = (row, index) => { if (!this.rowDetail) { return 0; } const rowHeight = this.rowDetail.rowHeight; return typeof rowHeight === 'function' ? rowHeight(row, index) : rowHeight; }; this.getGroupHeaderRowHeight = (row, index) => { if (!this.groupHeader) { return 0; } const rowHeight = this.groupHeader?.rowHeight === 0 ? this.rowHeight : this.groupHeader?.rowHeight; return typeof rowHeight === 'function' ? rowHeight(row, index) : rowHeight; }; // declare fn here so we can get access to the `this` property this.rowTrackingFn = (index, row) => { const idx = this.getRowIndex(row); if (this.trackByProp) { return row[this.trackByProp]; } else { return idx; } }; } /** * Called after the constructor, initializing input properties */ ngOnInit() { if (this.rowDetail) { this.listener = this.rowDetail.toggle.subscribe(({ type, value }) => this.toggleStateChange(type, value)); } if (this.groupHeader) { this.listener = this.groupHeader.toggle.subscribe(({ type, value }) => { // Remove default expansion state once user starts manual toggle. this.groupExpansionDefault = false; this.toggleStateChange(type, value); }); } } toggleStateChange(type, value) { if (type === 'group' || type === 'row') { this.toggleRowExpansion(value); } if (type === 'all') { this.toggleAllRows(value); } // Refresh rows after toggle // Fixes #883 this.updateIndexes(); this.updateRows(); this.cd.markForCheck(); } /** * Called once, before the instance is destroyed. */ ngOnDestroy() { if (this.rowDetail || this.groupHeader) { this.listener.unsubscribe(); } } /** * Updates the Y offset given a new offset. */ updateOffsetY(offset) { // scroller is missing on empty table if (!this.scroller) { return; } if (this.scrollbarV && this.virtualization && offset) { // First get the row Index that we need to move to. const rowIndex = this.pageSize * offset; offset = this.rowHeightsCache.query(rowIndex - 1); } else if (this.scrollbarV && !this.virtualization) { offset = 0; } this.scroller.setOffset(offset || 0); } /** * Body was scrolled, this is mainly useful for * when a user is server-side pagination via virtual scroll. */ onBodyScroll(event) { const scrollYPos = event.scrollYPos; const scrollXPos = event.scrollXPos; // if scroll change, trigger update // this is mainly used for header cell positions if (this.offsetY !== scrollYPos || this.offsetX !== scrollXPos) { this.scroll.emit({ offsetY: scrollYPos, offsetX: scrollXPos }); } this.offsetY = scrollYPos; this.offsetX = scrollXPos; this.updateIndexes(); this.updatePage(event.direction); this.updateRows(); this.cd.detectChanges(); } /** * Updates the page given a direction. */ updatePage(direction) { let offset = this.indexes.first / this.pageSize; const scrollInBetween = !Number.isInteger(offset); if (direction === 'up') { offset = Math.ceil(offset); } else if (direction === 'down') { offset = Math.floor(offset); } if (direction !== undefined && !isNaN(offset) && offset !== this._offsetEvent) { this._offsetEvent = offset; // if scroll was done by mouse drag make sure previous row and next row data is also fetched if its not fetched if (scrollInBetween && this.scrollbarV && this.virtualization && this.externalPaging) { const upRow = this.rows[this.indexes.first - 1]; if (!upRow && direction === 'up') { this.page.emit({ offset: offset - 1 }); } const downRow = this.rows[this.indexes.first + this.pageSize]; if (!downRow && direction === 'down') { this.page.emit({ offset: offset + 1 }); } } this.page.emit({ offset }); } } /** * Updates the rows in the view port */ updateRows() { const { first, last } = this.indexes; let rowIndex = first; let idx = 0; const temp = []; // if grouprowsby has been specified treat row paging // parameters as group paging parameters ie if limit 10 has been // specified treat it as 10 groups rather than 10 rows if (this.groupedRows) { let maxRowsPerGroup = 3; // if there is only one group set the maximum number of // rows per group the same as the total number of rows if (this.groupedRows.length === 1) { maxRowsPerGroup = this.groupedRows[0].value.length; } while (rowIndex < last && rowIndex < this.groupedRows.length) { // Add the groups into this page const group = this.groupedRows[rowIndex]; this.rowIndexes.set(group, rowIndex); if (group.value) { // add indexes for each group item group.value.forEach((g, i) => { const _idx = `${rowIndex}-${i}`; this.rowIndexes.set(g, _idx); }); } temp[idx] = group; idx++; // Group index in this context rowIndex++; } } else { while (rowIndex < last && rowIndex < this.rowCount) { const row = this.rows[rowIndex]; if (row) { // add indexes for each row this.rowIndexes.set(row, rowIndex); temp[idx] = row; } else if (this.ghostLoadingIndicator && this.virtualization) { temp[idx] = undefined; } idx++; rowIndex++; } } this.temp = temp; } /** * Get the row height */ getRowHeight(row) { // if its a function return it if (typeof this.rowHeight === 'function') { return this.rowHeight(row); } return this.rowHeight; } /** * @param group the group with all rows */ getGroupHeight(group) { let rowHeight = 0; if (group.value) { // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let index = 0; index < group.value.length; index++) { rowHeight += this.getRowAndDetailHeight(group.value[index]); } } return rowHeight; } /** * Calculate row height based on the expanded state of the row. */ getRowAndDetailHeight(row) { let rowHeight = this.getRowHeight(row); const expanded = this.getRowExpanded(row); // Adding detail row height if its expanded. if (expanded) { rowHeight += this.getDetailRowHeight(row); } return rowHeight; } /** * Calculates the styles for the row so that the rows can be moved in 2D space * during virtual scroll inside the DOM. In the below case the Y position is * manipulated. As an example, if the height of row 0 is 30 px and row 1 is * 100 px then following styles are generated: * * transform: translate3d(0px, 0px, 0px); -> row0 * transform: translate3d(0px, 30px, 0px); -> row1 * transform: translate3d(0px, 130px, 0px); -> row2 * * Row heights have to be calculated based on the row heights cache as we wont * be able to determine which row is of what height before hand. In the above * case the positionY of the translate3d for row2 would be the sum of all the * heights of the rows before it (i.e. row0 and row1). * * @param rows the row that needs to be placed in the 2D space. * @param index for ghost cells in order to get correct position of ghost row * @returns the CSS3 style to be applied * * @memberOf DataTableBodyComponent */ getRowsStyles(rows, index = 0) { const styles = {}; // only add styles for the group if there is a group if (this.groupedRows) { styles.width = this.columnGroupWidths.total; } if (this.scrollbarV && this.virtualization) { let idx = 0; if (this.groupedRows) { // Get the latest row rowindex in a group const row = rows[rows.length - 1]; idx = row ? this.getRowIndex(row) : 0; } else { if (rows) { idx = this.getRowIndex(rows); } else { // When ghost cells are enabled use index to get the position of them idx = index; } } // const pos = idx * rowHeight; // The position of this row would be the sum of all row heights // until the previous row position. const pos = this.rowHeightsCache.query(idx - 1); translateXY(styles, 0, pos); } return styles; } /** * Calculate bottom summary row offset for scrollbar mode. * For more information about cache and offset calculation * see description for `getRowsStyles` method * * @returns the CSS3 style to be applied * * @memberOf DataTableBodyComponent */ getBottomSummaryRowStyles() { if (!this.scrollbarV || !this.rows || !this.rows.length) { return null; } const styles = { position: 'absolute' }; const pos = this.rowHeightsCache.query(this.rows.length - 1); translateXY(styles, 0, pos); return styles; } /** * Hides the loading indicator */ hideIndicator() { setTimeout(() => (this.loadingIndicator = false), 500); } /** * Updates the index of the rows in the viewport */ updateIndexes() { let first = 0; let last = 0; if (this.scrollbarV) { if (this.virtualization) { // Calculation of the first and last indexes will be based on where the // scrollY position would be at. The last index would be the one // that shows up inside the view port the last. const height = parseInt(this.bodyHeight, 10); first = this.rowHeightsCache.getRowIndex(this.offsetY); last = this.rowHeightsCache.getRowIndex(height + this.offsetY) + 1; } else { // If virtual rows are not needed // We render all in one go first = 0; last = this.rowCount; } } else { // The server is handling paging and will pass an array that begins with the // element at a specified offset. first should always be 0 with external paging. if (!this.externalPaging) { first = Math.max(this.offset * this.pageSize, 0); } last = Math.min(first + this.pageSize, this.rowCount); } this.indexes = { first, last }; } /** * Refreshes the full Row Height cache. Should be used * when the entire row array state has changed. */ refreshRowHeightCache() { if (!this.scrollbarV || (this.scrollbarV && !this.virtualization)) { return; } // clear the previous row height cache if already present. // this is useful during sorts, filters where the state of the // rows array is changed. this.rowHeightsCache.clearCache(); // Initialize the tree only if there are rows inside the tree. if (this.rows && this.rows.length) { const rowExpansions = new Set(); for (const row of this.rows) { if (this.getRowExpanded(row)) { rowExpansions.add(row); } } this.rowHeightsCache.initCache({ rows: this.rows, rowHeight: this.rowHeight, detailRowHeight: this.getDetailRowHeight, externalVirtual: this.scrollbarV && this.externalPaging, rowCount: this.rowCount, rowIndexes: this.rowIndexes, rowExpansions }); } } /** * Gets the index for the view port */ getAdjustedViewPortIndex() { // Capture the row index of the first row that is visible on the viewport. // If the scroll bar is just below the row which is highlighted then make that as the // first index. const viewPortFirstRowIndex = this.indexes.first; if (this.scrollbarV && this.virtualization) { const offsetScroll = this.rowHeightsCache.query(viewPortFirstRowIndex - 1); return offsetScroll <= this.offsetY ? viewPortFirstRowIndex - 1 : viewPortFirstRowIndex; } return viewPortFirstRowIndex; } /** * Toggle the Expansion of the row i.e. if the row is expanded then it will * collapse and vice versa. Note that the expanded status is stored as * a part of the row object itself as we have to preserve the expanded row * status in case of sorting and filtering of the row set. */ toggleRowExpansion(row) { // Capture the row index of the first row that is visible on the viewport. const viewPortFirstRowIndex = this.getAdjustedViewPortIndex(); const rowExpandedIdx = this.getRowExpandedIdx(row, this.rowExpansions); const expanded = rowExpandedIdx > -1; // If the detailRowHeight is auto --> only in case of non-virtualized scroll if (this.scrollbarV && this.virtualization) { const detailRowHeight = this.getDetailRowHeight(row) * (expanded ? -1 : 1); // const idx = this.rowIndexes.get(row) || 0; const idx = this.getRowIndex(row); this.rowHeightsCache.update(idx, detailRowHeight); } // Update the toggled row and update thive nevere heights in the cache. if (expanded) { this.rowExpansions.splice(rowExpandedIdx, 1); } else { this.rowExpansions.push(row); } this.detailToggle.emit({ rows: [row], currentIndex: viewPortFirstRowIndex }); } /** * Expand/Collapse all the rows no matter what their state is. */ toggleAllRows(expanded) { // clear prev expansions this.rowExpansions = []; // Capture the row index of the first row that is visible on the viewport. const viewPortFirstRowIndex = this.getAdjustedViewPortIndex(); const rows = this.groupedRows ?? this.rows; if (expanded) { for (const row of rows) { this.rowExpansions.push(row); } } if (this.scrollbarV) { // Refresh the full row heights cache since every row was affected. this.recalcLayout(); } // Emit all rows that have been expanded. this.detailToggle.emit({ rows: rows, currentIndex: viewPortFirstRowIndex }); } /** * Recalculates the table */ recalcLayout() { this.refreshRowHeightCache(); this.updateIndexes(); this.updateRows(); } /** * Tracks the column */ columnTrackingFn(index, column) { return column.$$id; } /** * Gets the row pinning group styles */ stylesByGroup(group) { const widths = this.columnGroupWidths; const offsetX = this.offsetX; const styles = { width: `${widths[group]}px` }; if (group === 'left') { translateXY(styles, offsetX, 0); } else if (group === 'right') { const bodyWidth = this.innerWidth; const totalDiff = widths.total - bodyWidth; const offsetDiff = totalDiff - offsetX; const offset = offsetDiff * -1; translateXY(styles, offset, 0); } return styles; } /** * Returns if the row was expanded and set default row expansion when row expansion is empty */ getRowExpanded(row) { if (this.rowExpansions.length === 0 && this.groupExpansionDefault) { for (const group of this.groupedRows) { this.rowExpansions.push(group); } } return this.getRowExpandedIdx(row, this.rowExpansions) > -1; } getRowExpandedIdx(row, expanded) { if (!expanded || !expanded.length) { return -1; } const rowId = this.rowIdentity(row); return expanded.findIndex(r => { const id = this.rowIdentity(r); return id === rowId; }); } /** * Gets the row index given a row */ getRowIndex(row) { return this.rowIndexes.get(row) || 0; } onTreeAction(row) { this.treeAction.emit({ row }); } dragOver(event, dropRow) { event.preventDefault(); this.rowDragEvents.emit({ event, srcElement: this._draggedRowElement, eventType: 'dragover', dragRow: this._draggedRow, dropRow }); } drag(event, dragRow, rowComponent) { this._draggedRow = dragRow; this._draggedRowElement = rowComponent._element; this.rowDragEvents.emit({ event, srcElement: this._draggedRowElement, eventType: 'dragstart', dragRow }); } drop(event, dropRow, rowComponent) { event.preventDefault(); this.rowDragEvents.emit({ event, srcElement: this._draggedRowElement, targetElement: rowComponent._element, eventType: 'drop', dragRow: this._draggedRow, dropRow }); } dragEnter(event, dropRow, rowComponent) { event.preventDefault(); this.rowDragEvents.emit({ event, srcElement: this._draggedRowElement, targetElement: rowComponent._element, eventType: 'dragenter', dragRow: this._draggedRow, dropRow }); } dragLeave(event, dropRow, rowComponent) { event.preventDefault(); this.rowDragEvents.emit({ event, srcElement: this._draggedRowElement, targetElement: rowComponent._element, eventType: 'dragleave', dragRow: this._draggedRow, dropRow }); } dragEnd(event, dragRow) { event.preventDefault(); this.rowDragEvents.emit({ event, srcElement: this._draggedRowElement, eventType: 'dragend', dragRow }); this._draggedRow = undefined; this._draggedRowElement = undefined; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.6", ngImport: i0, type: DataTableBodyComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.6", type: DataTableBodyComponent, selector: "datatable-body", inputs: { rowDefTemplate: "rowDefTemplate", scrollbarV: "scrollbarV", scrollbarH: "scrollbarH", loadingIndicator: "loadingIndicator", ghostLoadingIndicator: "ghostLoadingIndicator", externalPaging: "externalPaging", rowHeight: "rowHeight", offsetX: "offsetX", emptyMessage: "emptyMessage", selectionType: "selectionType", selected: "selected", rowIdentity: "rowIdentity", rowDetail: "rowDetail", groupHeader: "groupHeader", selectCheck: "selectCheck", displayCheck: "displayCheck", trackByProp: "trackByProp", rowClass: "rowClass", groupedRows: "groupedRows", groupExpansionDefault: "groupExpansionDefault", innerWidth: "innerWidth", groupRowsBy: "groupRowsBy", virtualization: "virtualization", summaryRow: "summaryRow", summaryPosition: "summaryPosition", summaryHeight: "summaryHeight", rowDraggable: "rowDraggable", rowDragEvents: "rowDragEvents", disableRowCheck: "disableRowCheck", pageSize: "pageSize", rows: "rows", columns: "columns", offset: "offset", rowCount: "rowCount", bodyHeight: "bodyHeight", verticalScrollVisible: "verticalScrollVisible" }, outputs: { scroll: "scroll", page: "page", activate: "activate", select: "select", detailToggle: "detailToggle", rowContextmenu: "rowContextmenu", treeAction: "treeAction" }, host: { properties: { "style.width": "this.bodyWidth", "style.height": "this.bodyHeight" }, classAttribute: "datatable-body" }, viewQueries: [{ propertyName: "scroller", first: true, predicate: ScrollerComponent, descendants: true }], ngImport: i0, template: ` <ng-container *ngIf="loadingIndicator"> <div class="custom-loading-indicator-wrapper"> <div class="custom-loading-content" #customIndicator> <ng-content select="[loading-indicator]"></ng-content> </div> </div> <datatable-progress *ngIf="!customIndicator?.hasChildNodes()"></datatable-progress> </ng-container> <ghost-loader *ngIf="ghostLoadingIndicator && (!rowCount || !virtualization || !scrollbarV)" class="ghost-overlay" [columns]="columns" [pageSize]="pageSize" [rowHeight]="rowHeight" [ghostBodyHeight]="bodyHeight" > </ghost-loader> <datatable-selection #selector [selected]="selected" [rows]="rows" [selectCheck]="selectCheck" [disableCheck]="disableRowCheck" [selectEnabled]="selectEnabled" [selectionType]="selectionType" [rowIdentity]="rowIdentity" (select)="select.emit($event)" (activate)="activate.emit($event)" > <datatable-scroller *ngIf="rows?.length" [scrollbarV]="scrollbarV" [scrollbarH]="scrollbarH" [scrollHeight]="scrollHeight" [scrollWidth]="columnGroupWidths?.total" (scroll)="onBodyScroll($event)" > <datatable-summary-row *ngIf="summaryRow && summaryPosition === 'top'" [rowHeight]="summaryHeight" [offsetX]="offsetX" [innerWidth]="innerWidth" [rows]="rows" [columns]="columns" > </datatable-summary-row> <datatable-row-wrapper #rowWrapper [groupedRows]="groupedRows" *ngFor="let group of temp; let i = index; trackBy: rowTrackingFn" [innerWidth]="innerWidth" [ngStyle]="getRowsStyles(group, indexes.first + i )" [rowDetail]="rowDetail" [groupHeader]="groupHeader" [offsetX]="offsetX" [detailRowHeight]="getDetailRowHeight(group && group[i], i)" [groupHeaderRowHeight]="getGroupHeaderRowHeight(group && group[i], i)" [row]="group" [disableCheck]="disableRowCheck" [expanded]="getRowExpanded(group)" [rowIndex]="getRowIndex(group && group[i])" [selected]="selected" (rowContextmenu)="rowContextmenu.emit($event)" > <ng-container *ngIf="rowDefTemplate else bodyRow"> <ng-container *rowDefInternal="{ template: rowDefTemplate, rowTemplate: bodyRow, row: group, index: i }" /> </ng-container> <ng-template #bodyRow> <datatable-body-row role="row" *ngIf="!groupedRows; else groupedRowsTemplate" tabindex="-1" #rowElement [disable$]="rowWrapper.disable$" [isSelected]="selector.getRowSelected(group)" [innerWidth]="innerWidth" [offsetX]="offsetX" [columns]="columns" [rowHeight]="getRowHeight(group)" [row]="group" [rowIndex]="getRowIndex(group)" [expanded]="getRowExpanded(group)" [rowClass]="rowClass" [displayCheck]="displayCheck" [treeStatus]="group && group.treeStatus" [ghostLoadingIndicator]="ghostLoadingIndicator" [draggable]="rowDraggable" [verticalScrollVisible]="verticalScrollVisible" (treeAction)="onTreeAction(group)" (activate)="selector.onActivate($event, indexes.first + i)" (drop)="drop($event, group, rowElement)" (dragover)="dragOver($event, group)" (dragenter)="dragEnter($event, group, rowElement)" (dragleave)="dragLeave($event, group, rowElement)" (dragstart)="drag($event, group, rowElement)" (dragend)="dragEnd($event, group)" > </datatable-body-row> </ng-template> <ng-template #groupedRowsTemplate> <datatable-body-row role="row" [disable$]="rowWrapper.disable$" *ngFor="let row of group.value; let i = index; trackBy: rowTrackingFn" tabindex="-1" #rowElement [isSelected]="selector.getRowSelected(row)" [innerWidth]="innerWidth" [offsetX]="offsetX" [columns]="columns" [rowHeight]="getRowHeight(row)" [row]="row" [group]="group.value" [rowIndex]="getRowIndex(row)" [expanded]="getRowExpanded(row)" [rowClass]="rowClass" [ghostLoadingIndicator]="ghostLoadingIndicator" [draggable]="rowDraggable" [verticalScrollVisible]="verticalScrollVisible" (activate)="selector.onActivate($event, i)" (drop)="drop($event, row, rowElement)" (dragover)="dragOver($event, row)" (dragenter)="dragEnter($event, row, rowElement)" (dragleave)="dragLeave($event, row, rowElement)" (dragstart)="drag($event, row, rowElement)" (dragend)="dragEnd($event, row)" > </datatable-body-row> </ng-template> </datatable-row-wrapper> <datatable-summary-row role="row" *ngIf="summaryRow && summaryPosition === 'bottom'" [ngStyle]="getBottomSummaryRowStyles()" [rowHeight]="summaryHeight" [offsetX]="offsetX" [innerWidth]="innerWidth" [rows]="rows" [columns]="columns" > </datatable-summary-row> </datatable-scroller> <ng-container *ngIf="!rows?.length && !loadingIndicator && !ghostLoadingIndicator"> <datatable-scroller [scrollbarV]="scrollbarV" [scrollbarH]="scrollbarH" [scrollHeight]="scrollHeight" [style.width]="scrollbarH ? columnGroupWidths?.total + 'px' : '100%'" (scroll)="onBodyScroll($event)" > <div class="empty-row" *ngIf="!customEmptyContent?.children.length" [innerHTML]="emptyMessage" ></div> <div #customEmptyContent> <ng-content select="[empty-content]"></ng-content> </div> </datatable-scroller> </ng-container> </datatable-selection> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.DraggableDirective, selector: "[draggable]", inputs: ["dragEventTarget", "dragModel", "dragX", "dragY"], outputs: ["dragStart", "dragging", "dragEnd"] }, { kind: "component", type: i3.ScrollerComponent, selector: "datatable-scroller", inputs: ["scrollbarV", "scrollbarH", "scrollHeight", "scrollWidth"], outputs: ["scroll"] }, { kind: "component", type: i4.ProgressBarComponent, selector: "datatable-progress" }, { kind: "component", type: i5.DataTableBodyRowComponent, selector: "datatable-body-row", inputs: ["columns", "innerWidth", "expanded", "rowClass", "row", "group", "isSelected", "rowIndex", "displayCheck", "treeStatus", "ghostLoadingIndicator", "verticalScrollVisible", "disable$", "offsetX", "rowHeight"], outputs: ["activate", "treeAction"] }, { kind: "component", type: i6.DataTableRowWrapperComponent, selector: "datatable-row-wrapper", inputs: ["innerWidth", "rowDetail", "groupHeader", "offsetX", "detailRowHeight", "groupHeaderRowHeight", "row", "groupedRows", "disableCheck", "selected", "rowIndex", "expanded"], outputs: ["rowContextmenu"] }, { kind: "component", type: i7.DataTableSelectionComponent, selector: "datatable-selection", inputs: ["rows", "selected", "selectEnabled", "selectionType", "rowIdentity", "selectCheck", "disableCheck"], outputs: ["activate", "select"] }, { kind: "component", type: i8.DataTableSummaryRowComponent, selector: "datatable-summary-row", inputs: ["rows", "columns", "rowHeight", "offsetX", "innerWidth"] }, { kind: "component", type: i9.DataTableGhostLoaderComponent, selector: "ghost-loader", inputs: ["columns", "pageSize", "rowHeight", "ghostBodyHeight"] }, { kind: "directive", type: i10.DatatableRowDefInternalDirective, selector: "[rowDefInternal]", inputs: ["rowDefInternal"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.6", ngImport: i0, type: DataTableBodyComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-body', template: ` <ng-container *ngIf="loadingIndicator"> <div class="custom-loading-indicator-wrapper"> <div class="custom-loading-content" #customIndicator> <ng-content select="[loading-indicator]"></ng-content> </div> </div> <datatable-progress *ngIf="!customIndicator?.hasChildNodes()"></datatable-progress> </ng-container> <ghost-loader *ngIf="ghostLoadingIndicator && (!rowCount || !virtualization || !scrollbarV)" class="ghost-overlay" [columns]="columns" [pageSize]="pageSize" [rowHeight]="rowHeight" [ghostBodyHeight]="bodyHeight" > </ghost-loader> <datatable-selection #selector [selected]="selected" [rows]="rows" [selectCheck]="selectCheck" [disableCheck]="disableRowCheck" [selectEnabled]="selectEnabled" [selectionType]="selectionType" [rowIdentity]="rowIdentity" (select)="select.emit($event)" (activate)="activate.emit($event)" > <datatable-scroller *ngIf="rows?.length" [scrollbarV]="scrollbarV" [scrollbarH]="scrollbarH" [scrollHeight]="scrollHeight" [scrollWidth]="columnGroupWidths?.total" (scroll)="onBodyScroll($event)" > <datatable-summary-row *ngIf="summaryRow && summaryPosition === 'top'" [rowHeight]="summaryHeight" [offsetX]="offsetX" [innerWidth]="innerWidth" [rows]="rows" [columns]="columns" > </datatable-summary-row> <datatable-row-wrapper #rowWrapper [groupedRows]="groupedRows" *ngFor="let group of temp; let i = index; trackBy: rowTrackingFn" [innerWidth]="innerWidth" [ngStyle]="getRowsStyles(group, indexes.first + i )" [rowDetail]="rowDetail" [groupHeader]="groupHeader" [offsetX]="offsetX" [detailRowHeight]="getDetailRowHeight(group && group[i], i)" [groupHeaderRowHeight]="getGroupHeaderRowHeight(group && group[i], i)" [row]="group" [disableCheck]="disableRowCheck" [expanded]="getRowExpanded(group)" [rowIndex]="getRowIndex(group && group[i])" [selected]="selected" (rowContextmenu)="rowContextmenu.emit($event)" > <ng-container *ngIf="rowDefTemplate else bodyRow"> <ng-container *rowDefInternal="{ template: rowDefTemplate, rowTemplate: bodyRow, row: group, index: i }" /> </ng-container> <ng-template #bodyRow> <datatable-body-row role="row" *ngIf="!groupedRows; else groupedRowsTemplate" tabindex="-1" #rowElement [disable$]="rowWrapper.disable$" [isSelected]="selector.getRowSelected(group)" [innerWidth]="innerWidth" [offsetX]="offsetX" [columns]="columns" [rowHeight]="getRowHeight(group)" [row]="group" [rowIndex]="getRowIndex(group)" [expanded]="getRowExpanded(group)" [rowClass]="rowClass" [displayCheck]="displayCheck" [treeStatus]="group && group.treeStatus" [ghostLoadingIndicator]="ghostLoadingIndicator" [draggable]="rowDraggable" [verticalScrollVisible]="verticalScrollVisible" (treeAction)="onTreeAction(group)" (activate)="selector.onActivate($event, indexes.first + i)" (drop)="drop($event, group, rowElement)" (dragover)="dragOver($event, group)" (dragenter)="dragEnter($event, group, rowElement)" (dragleave)="dragLeave($event, group, rowElement)" (dragstart)="drag($event, group, rowElement)" (dragend)="dragEnd($event, group)" > </datatable-body-row> </ng-template> <ng-template #groupedRowsTemplate> <datatable-body-row role="row" [disable$]="rowWrapper.disable$" *ngFor="let row of group.value; let i = index; trackBy: rowTrackingFn" tabindex="-1" #rowElement [isSelected]="selector.getRowSelected(row)" [innerWidth]="innerWidth" [offsetX]="offsetX" [columns]="columns" [rowHeight]="getRowHeight(row)" [row]="row" [group]="group.value" [rowIndex]="getRowIndex(row)" [expanded]="getRowExpanded(row)" [rowClass]="rowClass" [ghostLoadingIndicator]="ghostLoadingIndicator" [draggable]="rowDraggable" [verticalScrollVisible]="verticalScrollVisible" (activate)="selector.onActivate($event, i)" (drop)="drop($event, row, rowElement)" (dragover)="dragOver($event, row)" (dragenter)="dragEnter($event, row, rowElement)" (dragleave)="dragLeave($event, row, rowElement)" (dragstart)="drag($event, row, rowElement)" (dragend)="dragEnd($event, row)" > </datatable-body-row> </ng-template> </datatable-row-wrapper> <datatable-summary-row role="row" *ngIf="summaryRow && summaryPosition === 'bottom'" [ngStyle]="getBottomSummaryRowStyles()" [rowHeight]="summaryHeight" [offsetX]="offsetX" [innerWidth]="innerWidth" [rows]="rows" [columns]="columns" > </datatable-summary-row> </datatable-scroller> <ng-container *ngIf="!rows?.length && !loadingIndicator && !ghostLoadingIndicator"> <datatable-scroller [scrollbarV]="scrollbarV" [scrollbarH]="scrollbarH" [scrollHeight]="scrollHeight" [style.width]="scrollbarH ? columnGroupWidths?.total + 'px' : '100%'" (scroll)="onBodyScroll($event)" > <div class="empty-row" *ngIf="!customEmptyContent?.children.length" [innerHTML]="emptyMessage" ></div> <div #customEmptyContent> <ng-content select="[empty-content]"></ng-content> </div> </datatable-scroller> </ng-container> </datatable-selection> `, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'datatable-body' } }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { rowDefTemplate: [{ type: Input }], scrollbarV: [{ type: Input }], scrollbarH: [{ type: Input }], loadingIndicator: [{ type: Input }], ghostLoadingIndicator: [{ type: Input }], externalPaging: [{ type: Input }], rowHeight: [{ type: Input }], offsetX: [{ type: Input }], emptyMessage: [{ type: Input }], selectionType: [{ type: Input }], selected: [{ type: Input }], rowIdentity: [{ type: Input }], rowDetail: [{ type: Input }], groupHeader: [{ type: Input }], selectCheck: [{ type: Input }], displayCheck: [{ type: Input }], trackByProp: [{ type: Input }], rowClass: [{ type: Input }], groupedRows: [{ type: Input }], groupExpansionDefault: [{ type: Input }], innerWidth: [{ type: Input }], groupRowsBy: [{ type: Input }], virtualization: [{ type: Input }], summaryRow: [{ type: Input }], summaryPosition: [{ type: Input }], summaryHeight: [{ type: Input }], rowDraggable: [{ type: Input }], rowDragEvents: [{ type: Input }], disableRowCheck: [{ type: Input }], pageSize: [{ type: Input }], rows: [{ type: Input }], columns: [{ type: Input }], offset: [{ type: Input }], rowCount: [{ type: Input }], bodyWidth: [{ type: HostBinding, args: ['style.width'] }], bodyHeight: [{ type: Input }, { type: HostBinding, args: ['style.height'] }], verticalScrollVisible: [{ type: Input }], scroll: [{ type: Output }], page: [{ type: Output }], activate: [{ type: Output }], select: [{ type: Output }], detailToggle: [{ type: Output }], rowContextmenu: [{ type: Output }], treeAction: [{ type: Output }], scroller: [{ type: ViewChild, args: [ScrollerComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9keS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZGF0YXRhYmxlL3NyYy9saWIvY29tcG9uZW50cy9ib2R5L2JvZHkuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUNULFlBQVksRUFDWixXQUFXLEVBQ1gsS0FBSyxFQUdMLE1BQU0sRUFFTixTQUFTLEVBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFekQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7Ozs7Ozs7Ozs7OztBQXVMcEQsTUFBTSxPQUFPLHNCQUFzQjtJQU1qQyxJQUFhLHFCQUFxQixDQUFDLEdBQVk7UUFDN0MsSUFBSSxDQUFDLHNCQUFzQixHQUFHLEdBQUcsQ0FBQztRQUNsQyxJQUFJLENBQUMsR0FBRyxFQUFFO1lBQ1IsNERBQTREO1lBQzVELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDOUM7SUFDSCxDQUFDO0lBQUEsQ0FBQztJQUNGLElBQUkscUJBQXFCO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUFDO0lBQ3JDLENBQUM7SUEwQkQsSUFBYSxRQUFRLENBQUMsR0FBVztRQUMvQixJQUFJLEdBQUcsS0FBSyxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQzFCLElBQUksQ0FBQyxTQUFTLEdBQUcsR0FBRyxDQUFDO1lBQ3JC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