UNPKG

@siemens/ngx-datatable

Version:

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

971 lines 147 kB
import { __decorate } from "tslib"; import { ChangeDetectionStrategy, Component, ContentChild, ContentChildren, ElementRef, EventEmitter, HostBinding, HostListener, Inject, Input, Optional, Output, SkipSelf, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; import { DatatableGroupHeaderDirective } from './body/body-group-header.directive'; import { BehaviorSubject } from 'rxjs'; import { groupRowsByParents, optionalGetterForProp } from '../utils/tree'; import { setColumnDefaults, translateTemplates } from '../utils/column-helper'; import { ColumnMode } from '../types/column-mode.type'; import { SelectionType } from '../types/selection.type'; import { SortType } from '../types/sort.type'; import { ContextmenuType } from '../types/contextmenu.type'; import { DataTableColumnDirective } from './columns/column.directive'; import { DatatableRowDetailDirective } from './row-detail/row-detail.directive'; import { DatatableFooterDirective } from './footer/footer.directive'; import { DataTableBodyComponent } from './body/body.component'; import { DataTableHeaderComponent } from './header/header.component'; import { throttleable } from '../utils/throttle'; import { adjustColumnWidths, forceFillColumnWidths } from '../utils/math'; import { sortGroupedRows, sortRows } from '../utils/sort'; import { DatatableRowDefDirective } from './body/body-row-def.component'; import { DatatableComponentToken } from '../utils/table-token'; import * as i0 from "@angular/core"; import * as i1 from "../services/scrollbar-helper.service"; import * as i2 from "../services/dimensions-helper.service"; import * as i3 from "../services/column-changes.service"; import * as i4 from "@angular/common"; import * as i5 from "../directives/visibility.directive"; import * as i6 from "./header/header.component"; import * as i7 from "./body/body.component"; import * as i8 from "./footer/footer.component"; export class DatatableComponent { /** * Rows that are displayed in the table. */ set rows(val) { this._rows = val; if (val) { this._internalRows = [...val]; } // auto sort on new updates if (!this.externalSorting) { this.sortInternalRows(); } // auto group by parent on new update this._internalRows = groupRowsByParents(this._internalRows, optionalGetterForProp(this.treeFromRelation), optionalGetterForProp(this.treeToRelation)); // recalculate sizes/etc this.recalculate(); if (this._rows && this._groupRowsBy) { // If a column has been specified in _groupRowsBy created a new array with the data grouped by that row this.groupedRows = this.groupArrayBy(this._rows, this._groupRowsBy); } this.cd.markForCheck(); } /** * Gets the rows. */ get rows() { return this._rows; } /** * This attribute allows the user to set the name of the column to group the data with */ set groupRowsBy(val) { if (val) { this._groupRowsBy = val; if (this._rows && this._groupRowsBy) { // cretes a new array with the data grouped this.groupedRows = this.groupArrayBy(this._rows, this._groupRowsBy); } } } get groupRowsBy() { return this._groupRowsBy; } /** * Columns to be displayed. */ set columns(val) { if (val) { this._internalColumns = [...val]; setColumnDefaults(this._internalColumns); this.recalculateColumns(); } this._columns = val; } /** * Get the columns. */ get columns() { return this._columns; } /** * The page size to be shown. * Default value: `undefined` */ set limit(val) { this._limit = val; // recalculate sizes/etc this.recalculate(); } /** * Gets the limit. */ get limit() { return this._limit; } /** * The total count of all rows. * Default value: `0` */ set count(val) { this._count = val; // recalculate sizes/etc this.recalculate(); } /** * Gets the count. */ get count() { return this._count; } /** * The current offset ( page - 1 ) shown. * Default value: `0` */ set offset(val) { this._offset = val; } get offset() { return Math.max(Math.min(this._offset, Math.ceil(this.rowCount / this.pageSize) - 1), 0); } /** * Show ghost loaders on each cell. * Default value: `false` */ set ghostLoadingIndicator(val) { this._ghostLoadingIndicator = val; if (val && this.scrollbarV && !this.externalPaging) { // in case where we don't have predefined total page length this.rows = [...(this.rows ?? []), undefined]; // undefined row will render ghost cell row at the end of the page } } ; get ghostLoadingIndicator() { return this._ghostLoadingIndicator; } /** * CSS class applied if the header height if fixed height. */ get isFixedHeader() { const headerHeight = this.headerHeight; return typeof headerHeight === 'string' ? headerHeight !== 'auto' : true; } /** * CSS class applied to the root element if * the row heights are fixed heights. */ get isFixedRow() { return this.rowHeight !== 'auto'; } /** * CSS class applied to root element if * vertical scrolling is enabled. */ get isVertScroll() { return this.scrollbarV; } /** * CSS class applied to root element if * virtualization is enabled. */ get isVirtualized() { return this.virtualization; } /** * CSS class applied to the root element * if the horziontal scrolling is enabled. */ get isHorScroll() { return this.scrollbarH; } /** * CSS class applied to root element is selectable. */ get isSelectable() { return this.selectionType !== undefined; } /** * CSS class applied to root is checkbox selection. */ get isCheckboxSelection() { return this.selectionType === SelectionType.checkbox; } /** * CSS class applied to root if cell selection. */ get isCellSelection() { return this.selectionType === SelectionType.cell; } /** * CSS class applied to root if single select. */ get isSingleSelection() { return this.selectionType === SelectionType.single; } /** * CSS class added to root element if mulit select */ get isMultiSelection() { return this.selectionType === SelectionType.multi; } /** * CSS class added to root element if mulit click select */ get isMultiClickSelection() { return this.selectionType === SelectionType.multiClick; } /** * Column templates gathered from `ContentChildren` * if described in your markup. */ set columnTemplates(val) { this._columnTemplates = val; this.translateColumns(val); } /** * Returns the column templates. */ get columnTemplates() { return this._columnTemplates; } /** * Returns if all rows are selected. */ get allRowsSelected() { let allRowsSelected = this.rows && this.selected && this.selected.length === this.rows.length; if (this.bodyComponent && this.selectAllRowsOnPage) { const indexes = this.bodyComponent.indexes; const rowsOnPage = indexes.last - indexes.first; allRowsSelected = this.selected.length === rowsOnPage; } return this.selected && this.rows && this.rows.length !== 0 && allRowsSelected; } constructor(scrollbarHelper, dimensionsHelper, cd, element, differs, columnChangesService, configuration) { this.scrollbarHelper = scrollbarHelper; this.dimensionsHelper = dimensionsHelper; this.cd = cd; this.columnChangesService = columnChangesService; this.configuration = configuration; /** * List of row objects that should be * represented as selected in the grid. * Default value: `[]` */ this.selected = []; /** * Enable vertical scrollbars */ this.scrollbarV = false; /** * Enable vertical scrollbars dynamically on demand. * Property `scrollbarV` needs to be set `true` too. * Width that is gained when no scrollbar is needed * is added to the inner table width. */ this.scrollbarVDynamic = false; /** * Enable horz scrollbars */ this.scrollbarH = false; /** * The row height; which is necessary * to calculate the height for the lazy rendering. */ this.rowHeight = 30; /** * Type of column width distribution formula. * Example: flex, force, standard */ this.columnMode = ColumnMode.standard; /** * The minimum header height in pixels. * Pass a falsey for no header */ this.headerHeight = 30; /** * The minimum footer height in pixels. * Pass falsey for no footer */ this.footerHeight = 0; /** * If the table should use external paging * otherwise its assumed that all data is preloaded. */ this.externalPaging = false; /** * If the table should use external sorting or * the built-in basic sorting. */ this.externalSorting = false; /** * Show the linear loading bar. * Default value: `false` */ this.loadingIndicator = false; /** * Enable/Disable ability to re-order columns * by dragging them. */ this.reorderable = true; /** * Swap columns on re-order columns or * move them. */ this.swapColumns = true; /** * The type of sorting */ this.sortType = SortType.single; /** * Array of sorted columns by property and type. * Default value: `[]` */ this.sorts = []; /** * Css class overrides */ this.cssClasses = { sortAscending: 'datatable-icon-up', sortDescending: 'datatable-icon-down', sortUnset: 'datatable-icon-sort-unset', pagerLeftArrow: 'datatable-icon-left', pagerRightArrow: 'datatable-icon-right', pagerPrevious: 'datatable-icon-prev', pagerNext: 'datatable-icon-skip' }; /** * Message overrides for localization * * emptyMessage [default] = 'No data to display' * totalMessage [default] = 'total' * selectedMessage [default] = 'selected' */ this.messages = { // Message to show when array is presented // but contains no values emptyMessage: 'No data to display', // Footer total message totalMessage: 'total', // Footer selected message selectedMessage: 'selected' }; /** * A boolean you can use to set the detault behaviour of rows and groups * whether they will start expanded or not. If ommited the default is NOT expanded. * */ this.groupExpansionDefault = false; /** * Property to which you can use for determining select all * rows on current page or not. * * @memberOf DatatableComponent */ this.selectAllRowsOnPage = false; /** * A flag for row virtualization on / off */ this.virtualization = true; /** * A flag for switching summary row on / off */ this.summaryRow = false; /** * A height of summary row */ this.summaryHeight = 30; /** * A property holds a summary row position: top/bottom */ this.summaryPosition = 'top'; /** * A flag to enable drag behavior of native HTML5 drag and drop API on rows. * If set to true, {@link rowDragEvents} will emit dragstart and dragend events. */ this.rowDraggable = false; /** * A flag to controll behavior of sort states. * By default sort on column toggles between ascending and descending without getting removed. * Set true to clear sorting of column after performing ascending and descending sort on that column. */ this.enableClearingSortState = false; /** * Body was scrolled typically in a `scrollbarV:true` scenario. */ this.scroll = new EventEmitter(); /** * A cell or row was focused via keyboard or mouse click. */ this.activate = new EventEmitter(); /** * A cell or row was selected. */ this.select = new EventEmitter(); /** * Column sort was invoked. */ this.sort = new EventEmitter(); /** * The table was paged either triggered by the pager or the body scroll. */ this.page = new EventEmitter(); /** * Columns were re-ordered. */ this.reorder = new EventEmitter(); /** * Column was resized. */ this.resize = new EventEmitter(); /** * The context menu was invoked on the table. * type indicates whether the header or the body was clicked. * content contains either the column or the row that was clicked. */ this.tableContextmenu = new EventEmitter(false); /** * A row was expanded ot collapsed for tree */ this.treeAction = new EventEmitter(); /** * Emits HTML5 native drag events. * Only emits dragenter, dragover, drop events by default. * Set {@link rowDraggble} to true for dragstart and dragend. */ this.rowDragEvents = new EventEmitter(); this.rowCount = 0; this._offsetX = new BehaviorSubject(0); this._count = 0; this._offset = 0; this._subscriptions = []; this._ghostLoadingIndicator = false; this.verticalScrollVisible = false; /** * This will be used when displaying or selecting rows. * when tracking/comparing them, we'll use the value of this fn, * * (`fn(x) === fn(y)` instead of `x === y`) */ this.rowIdentity = (x) => { if (this._groupRowsBy) { // each group in groupedRows are stored as {key, value: [rows]}, // where key is the groupRowsBy index return x.key ?? x; } else { return x; } }; // get ref to elm for measuring this.element = element.nativeElement; this.rowDiffer = differs.find({}).create(); // apply global settings from Module.forRoot if (this.configuration) { if (this.configuration.messages) { this.messages = { ...this.configuration.messages }; } if (this.configuration.cssClasses) { this.cssClasses = { ...this.configuration.cssClasses }; } this.headerHeight = this.configuration.headerHeight ?? this.headerHeight; this.footerHeight = this.configuration.footerHeight ?? this.footerHeight; this.rowHeight = this.configuration.rowHeight ?? this.rowHeight; } } /** * Lifecycle hook that is called after data-bound * properties of a directive are initialized. */ ngOnInit() { // need to call this immediatly to size // if the table is hidden the visibility // listener will invoke this itself upon show this.recalculate(); } /** * Lifecycle hook that is called after a component's * view has been fully initialized. */ ngAfterViewInit() { if (!this.externalSorting) { this.sortInternalRows(); } // this has to be done to prevent the change detection // tree from freaking out because we are readjusting if (typeof requestAnimationFrame === 'undefined') { return; } requestAnimationFrame(() => { this.recalculate(); // emit page for virtual server-side kickoff if (this.externalPaging && this.scrollbarV) { this.page.emit({ count: this.count, pageSize: this.pageSize, limit: this.limit, offset: 0 }); } }); } /** * Lifecycle hook that is called after a component's * content has been fully initialized. */ ngAfterContentInit() { this.columnTemplates.changes.subscribe(v => this.translateColumns(v)); this.listenForColumnInputChanges(); } /** * Translates the templates to the column objects */ translateColumns(val) { if (val) { const arr = val.toArray(); if (arr.length) { this._internalColumns = translateTemplates(arr); setColumnDefaults(this._internalColumns); this.recalculateColumns(); if (!this.externalSorting) { this.sortInternalRows(); } this.cd.markForCheck(); } } } /** * Creates a map with the data grouped by the user choice of grouping index * * @param originalArray the original array passed via parameter * @param groupBy the index of the column to group the data by */ groupArrayBy(originalArray, groupBy) { // create a map to hold groups with their corresponding results const map = new Map(); let i = 0; originalArray.forEach((item) => { const key = item[groupBy]; if (!map.has(key)) { map.set(key, [item]); } else { map.get(key).push(item); } i++; }); const addGroup = (key, value) => ({ key, value }); // convert map back to a simple array of objects return Array.from(map, x => addGroup(x[0], x[1])); } /* * Lifecycle hook that is called when Angular dirty checks a directive. */ ngDoCheck() { const rowDiffers = this.rowDiffer.diff(this.rows); if (rowDiffers || this.disableRowCheck) { if (!this.externalSorting) { this.sortInternalRows(); } else { this._internalRows = [...this.rows]; } // auto group by parent on new update this._internalRows = groupRowsByParents(this._internalRows, optionalGetterForProp(this.treeFromRelation), optionalGetterForProp(this.treeToRelation)); if (rowDiffers) { queueMicrotask(() => { this.recalculate(); this.cd.markForCheck(); }); } this.recalculatePages(); this.cd.markForCheck(); } } /** * Recalc's the sizes of the grid. * * Updated automatically on changes to: * * - Columns * - Rows * - Paging related * * Also can be manually invoked or upon window resize. */ recalculate() { this.recalculateDims(); this.recalculateColumns(); this.cd.markForCheck(); } /** * Window resize handler to update sizes. */ onWindowResize() { this.recalculate(); } /** * Recalulcates the column widths based on column width * distribution mode and scrollbar offsets. */ recalculateColumns(columns = this._internalColumns, forceIdx = -1, allowBleed = this.scrollbarH) { if (!columns) { return undefined; } let width = this._innerWidth; const bodyElement = this.bodyElement?.nativeElement; this.verticalScrollVisible = bodyElement?.scrollHeight > bodyElement?.clientHeight; if (this.scrollbarV && !this.scrollbarVDynamic) { width = width - (this.verticalScrollVisible ? this.scrollbarHelper.width : 0); } else if (this.scrollbarVDynamic) { const scrollerHeight = this.bodyComponent?.scroller?.element.offsetHeight; if (scrollerHeight && this.bodyHeight < scrollerHeight) { width = width - (this.verticalScrollVisible ? this.scrollbarHelper.width : 0); } if (this.headerComponent && this.headerComponent.innerWidth !== width) { this.headerComponent.innerWidth = width; } if (this.bodyComponent && this.bodyComponent.innerWidth !== width) { this.bodyComponent.innerWidth = width; this.bodyComponent.cd.markForCheck(); } } if (this.columnMode === ColumnMode.force) { forceFillColumnWidths(columns, width, forceIdx, allowBleed); } else if (this.columnMode === ColumnMode.flex) { adjustColumnWidths(columns, width); } return columns; } /** * Recalculates the dimensions of the table size. * Internally calls the page size and row count calcs too. * */ recalculateDims() { const dims = this.dimensionsHelper.getDimensions(this.element); this._innerWidth = Math.floor(dims.width); if (this.scrollbarV) { let height = dims.height; if (this.headerHeight) { height = height - this.headerHeight; } if (this.footerHeight) { height = height - this.footerHeight; } this.bodyHeight = height; } this.recalculatePages(); } /** * Recalculates the pages after a update. */ recalculatePages() { this.pageSize = this.calcPageSize(); this.rowCount = this.calcRowCount(); } /** * Body triggered a page event. */ onBodyPage({ offset }) { // Avoid pagination caming from body events like scroll when the table // has no virtualization and the external paging is enable. // This means, let's the developer handle pagination by my him(her) self if (this.externalPaging && !this.virtualization) { return; } this.offset = offset; if (!isNaN(this.offset)) { this.page.emit({ count: this.count, pageSize: this.pageSize, limit: this.limit, offset: this.offset }); } } /** * The body triggered a scroll event. */ onBodyScroll(event) { this._offsetX.next(event.offsetX); this.scroll.emit(event); this.cd.detectChanges(); } /** * The footer triggered a page event. */ onFooterPage(event) { this.offset = event.page - 1; this.bodyComponent.updateOffsetY(this.offset); this.page.emit({ count: this.count, pageSize: this.pageSize, limit: this.limit, offset: this.offset }); if (this.selectAllRowsOnPage) { this.selected = []; this.select.emit({ selected: this.selected }); } } /** * Recalculates the sizes of the page */ calcPageSize(val = this.rows) { // Keep the page size constant even if the row has been expanded. // This is because an expanded row is still considered to be a child of // the original row. Hence calculation would use rowHeight only. if (this.scrollbarV && this.virtualization) { const size = Math.ceil(this.bodyHeight / this.rowHeight); return Math.max(size, 0); } // if limit is passed, we are paging if (this.limit !== undefined) { return this.limit; } // otherwise use row length if (val) { return val.length; } // other empty :( return 0; } /** * Calculates the row count. */ calcRowCount(val = this.rows) { if (!this.externalPaging) { if (!val) { return 0; } if (this.groupedRows) { return this.groupedRows.length; } else if (this.treeFromRelation != null && this.treeToRelation != null) { return this._internalRows.length; } else { return val.length; } } return this.count; } /** * The header triggered a contextmenu event. */ onColumnContextmenu({ event, column }) { this.tableContextmenu.emit({ event, type: ContextmenuType.header, content: column }); } /** * The body triggered a contextmenu event. */ onRowContextmenu({ event, row }) { this.tableContextmenu.emit({ event, type: ContextmenuType.body, content: row }); } /** * The header triggered a column resize event. */ onColumnResize({ column, newValue }) { /* Safari/iOS 10.2 workaround */ if (column === undefined) { return; } let idx; const cols = this._internalColumns.map((c, i) => { c = { ...c }; if (c.$$id === column.$$id) { idx = i; c.width = newValue; // set this so we can force the column // width distribution to be to this value c.$$oldWidth = newValue; } return c; }); this.recalculateColumns(cols, idx); this._internalColumns = cols; this.resize.emit({ column, newValue }); } onColumnResizing({ column, newValue }) { if (column === undefined) { return; } column.width = newValue; column.$$oldWidth = newValue; const idx = this._internalColumns.indexOf(column); this.recalculateColumns(this._internalColumns, idx); } /** * The header triggered a column re-order event. */ onColumnReorder({ column, newValue, prevValue }) { const cols = this._internalColumns.map(c => ({ ...c })); if (this.swapColumns) { const prevCol = cols[newValue]; cols[newValue] = column; cols[prevValue] = prevCol; } else { if (newValue > prevValue) { const movedCol = cols[prevValue]; for (let i = prevValue; i < newValue; i++) { cols[i] = cols[i + 1]; } cols[newValue] = movedCol; } else { const movedCol = cols[prevValue]; for (let i = prevValue; i > newValue; i--) { cols[i] = cols[i - 1]; } cols[newValue] = movedCol; } } this._internalColumns = cols; this.reorder.emit({ column, newValue, prevValue }); } /** * The header triggered a column sort event. */ onColumnSort(event) { // clean selected rows if (this.selectAllRowsOnPage) { this.selected = []; this.select.emit({ selected: this.selected }); } this.sorts = event.sorts; // this could be optimized better since it will resort // the rows again on the 'push' detection... if (this.externalSorting === false) { // don't use normal setter so we don't resort this.sortInternalRows(); } // auto group by parent on new update this._internalRows = groupRowsByParents(this._internalRows, optionalGetterForProp(this.treeFromRelation), optionalGetterForProp(this.treeToRelation)); // Always go to first page when sorting to see the newly sorted data this.offset = 0; this.bodyComponent.updateOffsetY(this.offset); // Emit the page object with updated offset value this.page.emit({ count: this.count, pageSize: this.pageSize, limit: this.limit, offset: this.offset }); this.sort.emit(event); } /** * Toggle all row selection */ onHeaderSelect(event) { if (this.bodyComponent && this.selectAllRowsOnPage) { // before we splice, chk if we currently have all selected const first = this.bodyComponent.indexes.first; const last = this.bodyComponent.indexes.last; const allSelected = this.selected.length === last - first; // remove all existing either way this.selected = []; // do the opposite here if (!allSelected) { this.selected.push(...this._internalRows.slice(first, last)); } } else { let relevantRows; if (this.disableRowCheck) { relevantRows = this.rows.filter(row => !this.disableRowCheck(row)); } else { relevantRows = this.rows; } // before we splice, chk if we currently have all selected const allSelected = this.selected.length === relevantRows.length; // remove all existing either way this.selected = []; // do the opposite here if (!allSelected) { this.selected.push(...relevantRows); } } this.select.emit({ selected: this.selected }); } /** * A row was selected from body */ onBodySelect(event) { this.select.emit(event); } /** * A row was expanded or collapsed for tree */ onTreeAction(event) { const row = event.row; // TODO: For duplicated items this will not work const rowIndex = this._rows.findIndex(r => r[this.treeToRelation] === event.row[this.treeToRelation]); this.treeAction.emit({ row, rowIndex }); } ngOnDestroy() { this._subscriptions.forEach(subscription => subscription.unsubscribe()); } /** * listen for changes to input bindings of all DataTableColumnDirective and * trigger the columnTemplates.changes observable to emit */ listenForColumnInputChanges() { this._subscriptions.push(this.columnChangesService.columnInputChanges$.subscribe(() => { if (this.columnTemplates) { this.columnTemplates.notifyOnChanges(); } })); } sortInternalRows() { // if there are no sort criteria we reset the rows with original rows if (!this.sorts || !this.sorts?.length) { this._internalRows = this._rows; // if there is any tree relation then re-group rows accordingly if (this.treeFromRelation && this.treeToRelation) { this._internalRows = groupRowsByParents(this._internalRows, optionalGetterForProp(this.treeFromRelation), optionalGetterForProp(this.treeToRelation)); } } if (this.groupedRows && this.groupedRows.length) { const sortOnGroupHeader = this.sorts?.find(sortColumns => sortColumns.prop === this._groupRowsBy); this.groupedRows = this.groupArrayBy(this._rows, this._groupRowsBy); this.groupedRows = sortGroupedRows(this.groupedRows, this._internalColumns, this.sorts, sortOnGroupHeader); this._internalRows = [...this._internalRows]; } else { this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.6", ngImport: i0, type: DatatableComponent, deps: [{ token: i1.ScrollbarHelper, skipSelf: true }, { token: i2.DimensionsHelper, skipSelf: true }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.KeyValueDiffers }, { token: i3.ColumnChangesService }, { token: 'configuration', optional: true }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.6", type: DatatableComponent, selector: "ngx-datatable", inputs: { targetMarkerTemplate: "targetMarkerTemplate", rows: "rows", groupRowsBy: "groupRowsBy", groupedRows: "groupedRows", columns: "columns", selected: "selected", scrollbarV: "scrollbarV", scrollbarVDynamic: "scrollbarVDynamic", scrollbarH: "scrollbarH", rowHeight: "rowHeight", columnMode: "columnMode", headerHeight: "headerHeight", footerHeight: "footerHeight", externalPaging: "externalPaging", externalSorting: "externalSorting", limit: "limit", count: "count", offset: "offset", loadingIndicator: "loadingIndicator", ghostLoadingIndicator: "ghostLoadingIndicator", selectionType: "selectionType", reorderable: "reorderable", swapColumns: "swapColumns", sortType: "sortType", sorts: "sorts", cssClasses: "cssClasses", messages: "messages", rowClass: "rowClass", selectCheck: "selectCheck", displayCheck: "displayCheck", groupExpansionDefault: "groupExpansionDefault", trackByProp: "trackByProp", selectAllRowsOnPage: "selectAllRowsOnPage", virtualization: "virtualization", treeFromRelation: "treeFromRelation", treeToRelation: "treeToRelation", summaryRow: "summaryRow", summaryHeight: "summaryHeight", summaryPosition: "summaryPosition", disableRowCheck: "disableRowCheck", rowDraggable: "rowDraggable", enableClearingSortState: "enableClearingSortState", rowIdentity: "rowIdentity" }, outputs: { scroll: "scroll", activate: "activate", select: "select", sort: "sort", page: "page", reorder: "reorder", resize: "resize", tableContextmenu: "tableContextmenu", treeAction: "treeAction", rowDragEvents: "rowDragEvents" }, host: { listeners: { "window:resize": "onWindowResize()" }, properties: { "class.fixed-header": "this.isFixedHeader", "class.fixed-row": "this.isFixedRow", "class.scroll-vertical": "this.isVertScroll", "class.virtualized": "this.isVirtualized", "class.scroll-horz": "this.isHorScroll", "class.selectable": "this.isSelectable", "class.checkbox-selection": "this.isCheckboxSelection", "class.cell-selection": "this.isCellSelection", "class.single-selection": "this.isSingleSelection", "class.multi-selection": "this.isMultiSelection", "class.multi-click-selection": "this.isMultiClickSelection" }, classAttribute: "ngx-datatable" }, providers: [{ provide: DatatableComponentToken, useExisting: DatatableComponent }], queries: [{ propertyName: "rowDetail", first: true, predicate: DatatableRowDetailDirective, descendants: true }, { propertyName: "groupHeader", first: true, predicate: DatatableGroupHeaderDirective, descendants: true }, { propertyName: "footer", first: true, predicate: DatatableFooterDirective, descendants: true }, { propertyName: "rowDefTemplate", first: true, predicate: DatatableRowDefDirective, descendants: true, read: TemplateRef }, { propertyName: "columnTemplates", predicate: DataTableColumnDirective }], viewQueries: [{ propertyName: "bodyComponent", first: true, predicate: DataTableBodyComponent, descendants: true }, { propertyName: "headerComponent", first: true, predicate: DataTableHeaderComponent, descendants: true }, { propertyName: "bodyElement", first: true, predicate: DataTableBodyComponent, descendants: true, read: ElementRef }], ngImport: i0, template: "<div visibilityObserver (visible)=\"recalculate()\">\n <div role=\"table\">\n <datatable-header\n role=\"rowgroup\"\n *ngIf=\"headerHeight\"\n [sorts]=\"sorts\"\n [sortType]=\"sortType\"\n [scrollbarH]=\"scrollbarH\"\n [innerWidth]=\"_innerWidth\"\n [offsetX]=\"_offsetX | async\"\n [dealsWithGroup]=\"groupedRows !== undefined\"\n [columns]=\"_internalColumns\"\n [headerHeight]=\"headerHeight\"\n [reorderable]=\"reorderable\"\n [targetMarkerTemplate]=\"targetMarkerTemplate\"\n [sortAscendingIcon]=\"cssClasses.sortAscending\"\n [sortDescendingIcon]=\"cssClasses.sortDescending\"\n [sortUnsetIcon]=\"cssClasses.sortUnset\"\n [allRowsSelected]=\"allRowsSelected\"\n [selectionType]=\"selectionType\"\n [verticalScrollVisible]=\"verticalScrollVisible\"\n [enableClearingSortState]=\"enableClearingSortState\"\n (sort)=\"onColumnSort($event)\"\n (resize)=\"onColumnResize($event)\"\n (resizing)=\"onColumnResizing($event)\"\n (reorder)=\"onColumnReorder($event)\"\n (select)=\"onHeaderSelect($event)\"\n (columnContextmenu)=\"onColumnContextmenu($event)\"\n >\n </datatable-header>\n <datatable-body\n tabindex=\"0\"\n role=\"rowgroup\"\n [groupRowsBy]=\"groupRowsBy\"\n [groupedRows]=\"groupedRows\"\n [rows]=\"_internalRows\"\n [groupExpansionDefault]=\"groupExpansionDefault\"\n [scrollbarV]=\"scrollbarV\"\n [scrollbarH]=\"scrollbarH\"\n [virtualization]=\"virtualization\"\n [loadingIndicator]=\"loadingIndicator\"\n [ghostLoadingIndicator]=\"ghostLoadingIndicator\"\n [externalPaging]=\"externalPaging\"\n [rowHeight]=\"rowHeight\"\n [rowCount]=\"rowCount\"\n [offset]=\"offset\"\n [trackByProp]=\"trackByProp\"\n [columns]=\"_internalColumns\"\n [pageSize]=\"pageSize\"\n [offsetX]=\"_offsetX | async\"\n [rowDetail]=\"rowDetail\"\n [groupHeader]=\"groupHeader\"\n [selected]=\"selected\"\n [innerWidth]=\"_innerWidth\"\n [bodyHeight]=\"bodyHeight\"\n [selectionType]=\"selectionType\"\n [emptyMessage]=\"messages.emptyMessage\"\n [rowIdentity]=\"rowIdentity\"\n [rowClass]=\"rowClass\"\n [selectCheck]=\"selectCheck\"\n [displayCheck]=\"displayCheck\"\n [summaryRow]=\"summaryRow\"\n [summaryHeight]=\"summaryHeight\"\n [summaryPosition]=\"summaryPosition\"\n [verticalScrollVisible]=\"verticalScrollVisible\"\n (page)=\"onBodyPage($event)\"\n (activate)=\"activate.emit($event)\"\n (rowContextmenu)=\"onRowContextmenu($event)\"\n (select)=\"onBodySelect($event)\"\n (scroll)=\"onBodyScroll($event)\"\n (treeAction)=\"onTreeAction($event)\"\n [disableRowCheck]=\"disableRowCheck\"\n [rowDraggable]=\"rowDraggable\"\n [rowDragEvents]=\"rowDragEvents\"\n [rowDefTemplate]=\"rowDefTemplate\"\n >\n <ng-content select=\"[loading-indicator]\" ngProjectAs=\"[loading-indicator]\"></ng-content>\n <ng-content select=\"[empty-content]\" ngProjectAs=\"[empty-content]\"></ng-content>\n </datatable-body>\n </div>\n <datatable-footer\n *ngIf=\"footerHeight\"\n [rowCount]=\"groupedRows !== undefined ? _internalRows.length : rowCount\"\n [pageSize]=\"pageSize\"\n [offset]=\"offset\"\n [footerHeight]=\"footerHeight\"\n [footerTemplate]=\"footer\"\n [totalMessage]=\"messages.totalMessage\"\n [pagerLeftArrowIcon]=\"cssClasses.pagerLeftArrow\"\n [pagerRightArrowIcon]=\"cssClasses.pagerRightArrow\"\n [pagerPreviousIcon]=\"cssClasses.pagerPrevious\"\n [selectedCount]=\"selected.length\"\n [selectedMessage]=\"!!selectionType && messages.selectedMessage\"\n [pagerNextIcon]=\"cssClasses.pagerNext\"\n (page)=\"onFooterPage($event)\"\n >\n </datatable-footer>\n</div>\n", styles: [".ngx-datatable{display:block;overflow:hidden;justify-content:center;position:relative;transform:translateZ(0)}.ngx-datatable [hidden]{display:none!important}.ngx-datatable *,.ngx-datatable *:before,.ngx-datatable *:after{box-sizing:border-box}.ngx-datatable.scroll-vertical .datatable-body{overflow-y:auto}.ngx-datatable.scroll-vertical.virtualized .datatable-body .datatable-row-wrapper{position:absolute}.ngx-datatable.scroll-horz .datatable-body{overflow-x:auto;-webkit-overflow-scrolling:touch}.ngx-datatable.fixed-header .datatable-header .datatable-header-inner{white-space:nowrap}.ngx-datatable.fixed-header .datatable-header .datatable-header-inner .datatable-header-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ngx-datatable.fixed-row .datatable-scroll,.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row{white-space:nowrap}.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row .datatable-body-cell,.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row .datatable-body-group-cell{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ngx-datatable .datatable-body-row,.ngx-datatable .datatable-row-center,.ngx-datatable .datatable-header-inner{display:flex;flex-direction:row;-o-flex-flow:row;flex-flow:row}.ngx-datatable .datatable-body-cell,.ngx-datatable .datatable-header-cell{overflow-x:hidden;vertical-align:top;display:inline-block;line-height:1.625}.ngx-datatable .datatable-body-cell:focus,.ngx-datatable .datatable-header-cell:focus{outline:none}.ngx-datatable .datatable-row-left,.ngx-datatable .datatable-row-right{z-index:9}.ngx-datatable .datatable-row-left,.ngx-datatable .datatable-row-center,.ngx-datatable .datatable-row-group,.ngx-datatable .datatable-row-right{position:relative}.ngx-datatable .datatable-header{display:block;overflow:hidden}.ngx-datatable .datatable-header .datatable-header-inner{align-items:stretch;-webkit-align-items:stretch}.ngx-datatable .datatable-header .datatable-header-cell{position:relative;display:inline-block}.ngx-datatable .datatable-header .datatable-header-cell.sortable .datatable-header-cell-wrapper{cursor:pointer}.ngx-datatable .datatable-header .datatable-header-cell.longpress .datatable-header-cell-wrapper{cursor:move}.ngx-datatable .datatable-header .datatable-header-cell .sort-btn{line-height:100%;vertical-align:middle;display:inline-block;cursor:pointer}.ngx-datatable .datatable-header .datatable-header-cell .resize-handle,.ngx-datatable .datatable-header .datatable-header-cell .resize-handle--not-resizable{display:inline-block;position:absolute;right:0;top:0;bottom:0;width:5px;padding:0 4px;visibility:hidden}.ngx-datatable .datatable-header .datatable-header-cell .resize-handle{cursor:ew-resize}.ngx-datatable .datatable-header .datatable-header-cell.resizeable:hover .resize-handle,.ngx-datatable .datatable-header .datatable-header-cell:hover .resize-handle--not-resizable{visibility:visible}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker{position:absolute;top:0;bottom:0}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker.dragFromLeft{right:0}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker.dragFromRight{left:0}.ngx-datatable .datatable-header .datatable-header-cell .datatable-header-cell-template-wrap{height:inherit}.ngx-datatable .datatable-body{position:relative;z-index:10;display:block;overflow:hidden}.ngx-datatable .datatable-body .datatable-scroll{display:inline-block}.ngx-datatable .datatable-body .datatable-row-detail{overflow-y:hidden}.ngx-datatable .datatable-body .datatable-row-wrapper{display:flex;flex-direction:column}.ngx-datatable .datatable-body .datatable-body-row{outline:none}.ngx-datatable .datatable-body .datatable-body-row>div{display:flex}.ngx-datatable .datatable-footer{display:block;width:100%;overflow:auto}.ngx-datatable .datatable-footer .datatable-footer-inner{display:flex;align-items:center;width:100%}.ngx-datatable .datatable-footer .selected-count .page-count{flex:1 1 40%}.ngx-datatable .datatable-footer .selected-count .datatable-pager{flex:1 1 60%}.ngx-datatable .datatable-footer .page-count{flex:1 1 20%}.ngx-datatable .datatable-footer .datatable-pager{flex:1 1 80%;text-align:right}.ngx-datatable .datatable-footer .datatable-pager .pager,.ngx-datatable .datatable-footer .datatable-pager .pager li{padding:0;margin:0;display:inline-block;list-style:none}.ngx-datatable .datatable-footer .datatable-pager .pager li,.ngx-datatable .datatable-footer .datatable-pager .pager li a{outline:none}.ngx-datatable .datatable-footer .datatable-pager .pager li a{cursor:pointer;display:inline-block}.ngx-datatable .datatable-footer .datatable-pager .pager li.disabled a{cursor:not-allowed}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.VisibilityDirective, selector: "[visibilityObserver]", outputs: ["visible"] }, { kind: "component", type: i6.DataTableHeaderComponent, selector: "datatable-header", inputs: ["sortAscendingIcon", "sortDescendingIcon", "sortUnsetIcon", "scrollbarH", "dealsWithGroup", "targetMarkerTemplate", "enableClearingSortState", "innerWidth", "sorts", "sortType", "allRowsSelected", "selectionType", "reorderable", "verticalScrollVisible", "headerHeight", "columns", "offsetX"], outputs: ["sort", "reorder", "resize", "resizing", "select", "columnContextmenu"] }, { kind: "component", type: i7.DataTableBodyComponent, selector: "datatable-body", inputs: ["rowDefTemplate", "scrollbarV", "scrollbarH", "loadingIndicator", "ghostLoadingIndicator", "externalPaging", "rowHeight", "offsetX", "emptyMessage", "selectionType", "selected", "rowIdentity", "rowDetail", "groupHeader", "selectCheck", "displayCheck", "trackByProp", "rowClass", "groupedRows", "groupExpansionDefault", "innerWidth", "groupRowsBy", "virtualization", "summaryRow", "summaryPosition", "summaryHeight", "rowDraggable", "rowDragEvents", "disableRowCheck", "pageSize", "rows", "columns", "offset", "rowCount", "bodyHeight", "verticalScrollVisible"], outputs: ["scroll", "page", "activate", "select", "detailToggle", "rowContextmenu", "treeAction"] }, { kind: "component", type: i8.DataTableFooterComponent, selector: "datatable-footer", inputs: ["footerHeight", "rowCount", "pageSize", "offset", "pagerLeftArrowIcon", "pagerRightArrowIcon", "pagerPreviousIcon", "pagerNextIcon", "totalMessage", "footerTemplate", "selectedCount", "selectedMessage"], outputs: ["page"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } __decorate([ throttleable(5) ], DatatableComponent.prototype, "onWindowResize", null); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.6", ngImport: i0, type: DatatableComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-datatable', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'ngx-datatable' }, providers: [{ provide: DatatableComponentToken, useExisting: DatatableComponent }], template: "<div visibilityObserver (visible)=\"recalculate()\">\n <div role=\"table\">\n <datatable-header\n role=\"rowgroup\"\n *ngIf=\"headerHeight\"\n [sorts]=\"sorts\"\n [sortType]=\"sortType\"\n [scrollbarH]=\"scrollbarH\"\n [innerWidth]=\"_innerWidth\"\n [offsetX]=\"_offsetX | async\"\n [dealsWithGroup]=\"groupedRows !== undefined\"\n [columns]=\"_internalColumns\"\n [headerHeight]=\"headerHeight\"\n [reorderable]=\"reorderable\"\n [targetMarkerTemplate]=\"targetMarkerTemplate\"\n [sortAscendingIcon]=\"cssClasses.sortAscending\"\n [sortDescendingIcon]=\"cssClasses.sortDescending\"\n [sortUnsetIcon]=\"cssClasses.sortUnset\"\n [allRowsSelected]=\"allRowsSelected\"\n [selectionType]=\"selectionType\"\n [verticalScrollVisible]=\"verticalScrollVisible\"\n [enableClearingSortState]=\"enableClearingSortState\"\n (sort)=\"onColumnSort($event)\"\n (resize)=\"onColumnResize($event)\"\n (resizing)=\"onColumnResizing($event)\"\n (reorder)=\"onColumnReorder($event)\"\n (select)=\"onHeaderSelect($event)\"\n (columnContextmenu)=\"onColumnContextmenu($event)\"\n >\n </datatable-header>\n <datatable-body\n tabindex=\"0\"\n role=\"rowgroup\"\n [groupRowsBy]=\"groupRowsBy\"\n [groupedRows]=\"groupedRows\"\n [rows]=\"_internalRows\"\n [groupExpansionDefault]=\"groupExpansionDefault\"\n [scrollbarV]=\"scrollbarV\"\n [scrollbarH]=\"scrollbarH\"\n [virtualization]=\"virtualization\"\n [loadingIndicator]=\"loadingIndicator\"\n [ghostLoadingIndicator]=\"ghostLoadingIndicator\"\n [externalPaging]=\"externalPaging\"\n [rowHeight]=\"rowHeight\"\n [rowCount]=\"rowCount\"\n [offset]=\"offset\"\n [trackByProp]=\"trackByProp\"\n [columns]=\"_internalColumns\"\n [pageSize]=\"pageSize\"\n [offsetX]=\"_offsetX | async\"\n [rowDetail]=\"rowDetail\"\n [groupHeader]=\"groupHeader\"\n [selected]=\"selected\"\n [innerWidth]=\"_innerWidth\"\n [bodyHeight]=\"bodyHeight\"\n [selectionType]=\"selectionType\"\n [emptyMessage]=\"messages.emptyMessage\"\n [rowIdentity]=\"rowIdentity\"\n [rowClass]=\"rowClass\"\n [selectCheck]=\"selectCheck\"\n [displayCheck]=\"displayCheck\"\n [summaryRow]=\"summaryRow\"\n [summaryHeight]=\"summaryHeight\"\n [summaryPosition]=\"summaryPosition\"\n [verticalScrollVisible]=\"ve