@swimlane/ngx-datatable
Version:
ngx-datatable is an Angular table grid component for presenting large and complex data.
925 lines • 104 kB
JavaScript
import { __decorate } from "tslib";
import { Component, Input, Output, ElementRef, EventEmitter, ViewChild, HostListener, ContentChildren, HostBinding, ContentChild, KeyValueDiffers, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, SkipSelf, Optional, Inject } 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 { ScrollbarHelper } from '../services/scrollbar-helper.service';
import { ColumnChangesService } from '../services/column-changes.service';
import { DimensionsHelper } from '../services/dimensions-helper.service';
import { throttleable } from '../utils/throttle';
import { forceFillColumnWidths, adjustColumnWidths } from '../utils/math';
import { sortRows } from '../utils/sort';
export class DatatableComponent {
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 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';
/**
* 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();
this.rowCount = 0;
this._offsetX = new BehaviorSubject(0);
this._count = 0;
this._offset = 0;
this._subscriptions = [];
/**
* 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;
}
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 && this.configuration.messages) {
this.messages = Object.assign({}, this.configuration.messages);
}
}
/**
* 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);
}
/**
* 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;
}
/**
* 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();
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 groupByIndex 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) => {
return { 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() {
if (this.rowDiffer.diff(this.rows)) {
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));
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;
if (this.scrollbarV) {
width = width - this.scrollbarHelper.width;
}
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;
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 = Object.assign({}, 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
});
}
/**
* The header triggered a column re-order event.
*/
onColumnReorder({ column, newValue, prevValue }) {
const cols = this._internalColumns.map(c => {
return Object.assign({}, 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);
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 {
// before we splice, chk if we currently have all selected
const allSelected = this.selected.length === this.rows.length;
// remove all existing either way
this.selected = [];
// do the opposite here
if (!allSelected) {
this.selected.push(...this.rows);
}
}
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() {
this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
}
}
DatatableComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-datatable',
template: "<div role=\"table\" visibilityObserver (visible)=\"recalculate()\">\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 (sort)=\"onColumnSort($event)\"\n (resize)=\"onColumnResize($event)\"\n (reorder)=\"onColumnReorder($event)\"\n (select)=\"onHeaderSelect($event)\"\n (columnContextmenu)=\"onColumnContextmenu($event)\"\n >\n </datatable-header>\n <datatable-body\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 [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 (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 >\n </datatable-body>\n <datatable-footer\n *ngIf=\"footerHeight\"\n [rowCount]=\"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",
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
host: {
class: 'ngx-datatable'
},
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 :after,.ngx-datatable :before{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-header-inner,.ngx-datatable .datatable-row-center{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-center,.ngx-datatable .datatable-row-group,.ngx-datatable .datatable-row-left,.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}.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}"]
},] }
];
DatatableComponent.ctorParameters = () => [
{ type: ScrollbarHelper, decorators: [{ type: SkipSelf }] },
{ type: DimensionsHelper, decorators: [{ type: SkipSelf }] },
{ type: ChangeDetectorRef },
{ type: ElementRef },
{ type: KeyValueDiffers },
{ type: ColumnChangesService },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: ['configuration',] }] }
];
DatatableComponent.propDecorators = {
targetMarkerTemplate: [{ type: Input }],
rows: [{ type: Input }],
groupRowsBy: [{ type: Input }],
groupedRows: [{ type: Input }],
columns: [{ type: Input }],
selected: [{ type: Input }],
scrollbarV: [{ type: Input }],
scrollbarH: [{ type: Input }],
rowHeight: [{ type: Input }],
columnMode: [{ type: Input }],
headerHeight: [{ type: Input }],
footerHeight: [{ type: Input }],
externalPaging: [{ type: Input }],
externalSorting: [{ type: Input }],
limit: [{ type: Input }],
count: [{ type: Input }],
offset: [{ type: Input }],
loadingIndicator: [{ type: Input }],
selectionType: [{ type: Input }],
reorderable: [{ type: Input }],
swapColumns: [{ type: Input }],
sortType: [{ type: Input }],
sorts: [{ type: Input }],
cssClasses: [{ type: Input }],
messages: [{ type: Input }],
rowClass: [{ type: Input }],
selectCheck: [{ type: Input }],
displayCheck: [{ type: Input }],
groupExpansionDefault: [{ type: Input }],
trackByProp: [{ type: Input }],
selectAllRowsOnPage: [{ type: Input }],
virtualization: [{ type: Input }],
treeFromRelation: [{ type: Input }],
treeToRelation: [{ type: Input }],
summaryRow: [{ type: Input }],
summaryHeight: [{ type: Input }],
summaryPosition: [{ type: Input }],
scroll: [{ type: Output }],
activate: [{ type: Output }],
select: [{ type: Output }],
sort: [{ type: Output }],
page: [{ type: Output }],
reorder: [{ type: Output }],
resize: [{ type: Output }],
tableContextmenu: [{ type: Output }],
treeAction: [{ type: Output }],
isFixedHeader: [{ type: HostBinding, args: ['class.fixed-header',] }],
isFixedRow: [{ type: HostBinding, args: ['class.fixed-row',] }],
isVertScroll: [{ type: HostBinding, args: ['class.scroll-vertical',] }],
isVirtualized: [{ type: HostBinding, args: ['class.virtualized',] }],
isHorScroll: [{ type: HostBinding, args: ['class.scroll-horz',] }],
isSelectable: [{ type: HostBinding, args: ['class.selectable',] }],
isCheckboxSelection: [{ type: HostBinding, args: ['class.checkbox-selection',] }],
isCellSelection: [{ type: HostBinding, args: ['class.cell-selection',] }],
isSingleSelection: [{ type: HostBinding, args: ['class.single-selection',] }],
isMultiSelection: [{ type: HostBinding, args: ['class.multi-selection',] }],
isMultiClickSelection: [{ type: HostBinding, args: ['class.multi-click-selection',] }],
columnTemplates: [{ type: ContentChildren, args: [DataTableColumnDirective,] }],
rowDetail: [{ type: ContentChild, args: [DatatableRowDetailDirective,] }],
groupHeader: [{ type: ContentChild, args: [DatatableGroupHeaderDirective,] }],
footer: [{ type: ContentChild, args: [DatatableFooterDirective,] }],
bodyComponent: [{ type: ViewChild, args: [DataTableBodyComponent,] }],
headerComponent: [{ type: ViewChild, args: [DataTableHeaderComponent,] }],
rowIdentity: [{ type: Input }],
onWindowResize: [{ type: HostListener, args: ['window:resize',] }]
};
__decorate([
throttleable(5)
], DatatableComponent.prototype, "onWindowResize", null);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXRhYmxlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3N3aW1sYW5lL25neC1kYXRhdGFibGUvc3JjL2xpYi9jb21wb25lbnRzL2RhdGF0YWJsZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixVQUFVLEVBQ1YsWUFBWSxFQUNaLFNBQVMsRUFDVCxZQUFZLEVBQ1osZUFBZSxFQUlmLFdBQVcsRUFDWCxZQUFZLEVBRVosZUFBZSxFQUVmLGlCQUFpQixFQUNqQix1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFFBQVEsRUFDUixRQUFRLEVBQ1IsTUFBTSxFQUNQLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSw2QkFBNkIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBRW5GLE9BQU8sRUFBRSxlQUFlLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBRXJELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUxRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMvRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDdEUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDaEYsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sMkJBQTJC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