@alfiob/ng-datatable
Version:
ng-datatable - fully customizable & easy to use datatable library
668 lines • 162 kB
JavaScript
import { ChangeDetectionStrategy, Component, ContentChildren, EventEmitter, Input, Output, ViewChild, ViewEncapsulation, } from '@angular/core';
import { Pager } from './modals';
import { SlotDirective } from './slot.directive';
import * as i0 from "@angular/core";
import * as i1 from "@angular/platform-browser";
import * as i2 from "@angular/common";
import * as i3 from "@angular/forms";
import * as i4 from "./column-header";
import * as i5 from "./icon-check";
import * as i6 from "./icon-loader";
export class NgDataTableComponent {
constructor(sanitizer) {
this.sanitizer = sanitizer;
// props
this.loading = false;
this.isServerMode = false;
this.skin = 'bh-table-striped bh-table-hover';
this.totalRows = 0;
this.rows = [];
this.columns = [];
this.hasCheckbox = false;
this.search = '';
this.page = 1;
this.pageSize = 10;
this.pageSizeOptions = [10, 20, 30, 50, 100];
this.showPageSize = true;
this.rowClass = '';
this.cellClass = '';
this.sortable = false;
this.sortColumn = 'id';
this.sortDirection = 'asc';
this.columnFilter = false;
this.pagination = true;
this.showNumbers = true;
this.showNumbersCount = 5;
this.showFirstPage = true;
this.showLastPage = true;
this.firstArrow = '';
this.lastArrow = '';
this.nextArrow = '';
this.previousArrow = '';
this.paginationInfo = 'Showing {0} to {1} of {2} entries';
this.noDataContent = 'No data available';
this.stickyHeader = false;
this.height = '500px';
this.stickyFirstColumn = false;
this.cloneHeaderInFooter = false;
this.selectRowOnClick = false;
// events
this.changeServer = new EventEmitter();
this.sortChange = new EventEmitter();
this.searchChange = new EventEmitter();
this.pageChange = new EventEmitter();
this.pageSizeChange = new EventEmitter();
this.rowSelect = new EventEmitter();
this.filterChange = new EventEmitter();
this.rowClick = new EventEmitter();
this.rowDBClick = new EventEmitter();
// variables
this.filterItems = [];
this.currentPage = this.page;
this.currentPageSize = this.pagination ? this.pageSize : this.rows.length;
this.oldPageSize = this.pageSize;
this.currentSortColumn = this.sortColumn;
this.oldSortColumn = this.sortColumn;
this.currentSortDirection = this.sortDirection;
this.oldSortDirection = this.sortDirection;
this.filterRowCount = this.totalRows;
this.selectedAll = null;
this.currentLoader = this.loading;
this.currentSearch = this.search;
this.uniqueKey = '';
this.pager = new Pager();
//row click
this.timer = null;
this.delay = 230;
this.slotsMap = new Map();
}
ngOnInit() {
this.initDeafultValues();
this.changeRows();
}
ngOnChanges(changes) {
// watch loading
if (changes['loading'] && !changes['loading'].firstChange) {
this.currentLoader = this.loading;
}
// watch rows and columns
if ((changes['rows'] && !changes['rows'].firstChange) || (changes['columns'] && !changes['columns'].firstChange)) {
if (!this.isServerMode) {
this.currentPage = 1;
this.oldColumns = this.noReact(this.columns);
}
this.changeRows();
}
// watch page
if (!this.isServerMode) {
if (changes['page'] && !changes['page'].firstChange) {
this.movePage(this.page);
}
}
// watch pagesize
if (changes['pageSize'] && !changes['pageSize'].firstChange) {
this.currentPageSize = this.pagination ? this.pageSize : this.rows.length;
if (!this.isServerMode) {
this.changePageSize();
}
}
// watch search
if (changes['search'] && !changes['search'].firstChange) {
this.currentSearch = this.search;
this.changeSearch();
}
// watch sort column and direction
if (!this.isServerMode) {
if ((changes['sortColumn'] && !changes['sortColumn'].firstChange) || (changes['sortDirection'] && !changes['sortDirection'].firstChange)) {
this.sortChangeMethod(this.sortColumn, this.sortDirection);
}
}
}
initDeafultValues() {
this.currentLoader = this.loading;
this.currentSearch = this.search;
this.currentSortColumn = this.sortColumn;
this.currentSortDirection = this.sortDirection;
this.filterRowCount = this.totalRows;
this.currentPage = this.page;
if (this.pagination) {
const exists = this.pageSizeOptions.find((d) => d === this.pageSize);
this.currentPageSize = exists ? this.pageSize : 10;
}
else {
this.currentPageSize = this.rows.length;
}
this.oldPageSize = this.pageSize;
this.oldSortColumn = this.sortColumn;
this.oldSortDirection = this.sortDirection;
// set default columns values
for (const item of this.columns || []) {
const type = item.type?.toLowerCase() || 'string';
item.type = type;
item.isUnique = item.isUnique !== undefined ? item.isUnique : false;
item.hide = item.hide !== undefined ? item.hide : false;
item.filter = item.filter !== undefined ? item.filter : true;
item.search = item.search !== undefined ? item.search : true;
item.sort = item.sort !== undefined ? item.sort : true;
item.html = item.html !== undefined ? item.html : false;
item.condition = !type || type === 'string' ? 'contain' : 'equal';
}
this.oldColumns = this.noReact(this.columns);
this.setUniqueKey();
}
get getProps() {
return {
loading: this.currentLoader,
isServerMode: this.isServerMode,
skin: this.skin,
totalRows: this.filterRowCount,
rows: this.rows,
columns: this.columns,
hasCheckbox: this.hasCheckbox,
search: this.currentSearch,
page: this.currentPage,
pageSize: this.currentPageSize,
pageSizeOptions: this.pageSizeOptions,
showPageSize: this.showPageSize,
rowClass: this.rowClass,
cellClass: this.cellClass,
sortable: this.sortable,
sortColumn: this.currentSortColumn,
sortDirection: this.currentSortDirection,
columnFilter: this.columnFilter,
pagination: this.pagination,
showNumbers: this.showNumbers,
showNumbersCount: this.showNumbersCount,
showFirstPage: this.showFirstPage,
showLastPage: this.showLastPage,
firstArrow: this.firstArrow,
lastArrow: this.lastArrow,
nextArrow: this.nextArrow,
previousArrow: this.previousArrow,
paginationInfo: this.paginationInfo,
noDataContent: this.noDataContent,
stickyHeader: this.stickyHeader,
height: this.height,
stickyFirstColumn: this.stickyFirstColumn,
cloneHeaderInFooter: this.cloneHeaderInFooter,
selectRowOnClick: this.selectRowOnClick,
};
}
isFunction(value) {
return typeof value === 'function';
}
stringFormat() {
const args = [this.filterRowCount ? this.offset() : 0, this.limit(), this.filterRowCount];
return this.paginationInfo.replace(/{(\d+)}/g, (match, number) => {
return typeof args[number] != 'undefined' ? args[number] : match;
});
}
setUniqueKey() {
const col = this.columns.find((d) => d.isUnique);
this.uniqueKey = col?.field || '';
}
maxPage() {
const totalPages = this.currentPageSize < 1 ? 1 : Math.ceil(this.filterRowCount / this.currentPageSize);
return Math.max(totalPages || 0, 1);
}
offset() {
return (this.currentPage - 1) * this.currentPageSize + 1;
}
limit() {
const limit = this.currentPage * this.currentPageSize;
return this.filterRowCount >= limit ? limit : this.filterRowCount;
}
getPager() {
// total pages
let totalPages = this.maxPage();
// pages
let startPage, endPage;
let isMaxSized = typeof this.showNumbersCount !== 'undefined' && this.showNumbersCount < totalPages;
// recompute if maxSize
if (isMaxSized) {
// Current page is displayed in the middle of the visible ones
startPage = Math.max(this.currentPage - Math.floor(this.showNumbersCount / 2), 1);
endPage = startPage + this.showNumbersCount - 1;
// Adjust if limit is exceeded
if (endPage > totalPages) {
endPage = totalPages;
startPage = endPage - this.showNumbersCount + 1;
}
}
else {
startPage = 1;
endPage = totalPages;
}
const pages = Array.from(Array(endPage + 1 - startPage).keys()).map((i) => startPage + i);
return {
totalRows: this.isServerMode ? this.totalRows : this.filterItems.length,
currentPage: this.currentPage,
pageSize: this.pageSize,
maxPage: totalPages,
startPage: startPage,
endPage: endPage,
stringFormat: this.stringFormat(),
pages: pages,
};
}
setPager() {
this.pager = this.getPager();
}
filterRows() {
let result = [];
let rows = this.rows || [];
if (this.isServerMode) {
this.filterRowCount = this.totalRows || 0;
result = rows;
}
else {
this.columns?.forEach((d) => {
if (d.filter && ((d.value !== undefined && d.value !== null && d.value !== '') || d.condition === 'is_null' || d.condition === 'is_not_null')) {
// string filters
if (d.type === 'string') {
if (d.value && !d.condition) {
d.condition = 'contain';
}
if (d.condition === 'contain') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field)?.toString().toLowerCase().includes(d.value.toLowerCase());
});
}
else if (d.condition === 'not_contain') {
rows = rows.filter((item) => {
return !this.cellValue(item, d.field)?.toString().toLowerCase().includes(d.value.toLowerCase());
});
}
else if (d.condition === 'equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field)?.toString().toLowerCase() === d.value.toLowerCase();
});
}
else if (d.condition === 'not_equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field)?.toString().toLowerCase() !== d.value.toLowerCase();
});
}
else if (d.condition === 'start_with') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field)?.toString().toLowerCase().indexOf(d.value.toLowerCase()) === 0;
});
}
else if (d.condition === 'end_with') {
rows = rows.filter((item) => {
return (this.cellValue(item, d.field)
?.toString()
.toLowerCase()
.substr(d.value.length * -1) === d.value.toLowerCase());
});
}
}
// number filters
else if (d.type === 'number') {
if (d.value && !d.condition) {
d.condition = 'equal';
}
if (d.condition === 'equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) === parseFloat(d.value);
});
}
else if (d.condition === 'not_equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) !== parseFloat(d.value);
});
}
else if (d.condition === 'greater_than') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) > parseFloat(d.value);
});
}
else if (d.condition === 'greater_than_equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) >= parseFloat(d.value);
});
}
else if (d.condition === 'less_than') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) < parseFloat(d.value);
});
}
else if (d.condition === 'less_than_equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) <= parseFloat(d.value);
});
}
}
// date filters
if (d.type === 'date') {
if (d.value && !d.condition) {
d.condition = 'equal';
}
if (d.condition === 'equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && this.dateFormat(this.cellValue(item, d.field)) === d.value;
});
}
else if (d.condition === 'not_equal') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && this.dateFormat(this.cellValue(item, d.field)) !== d.value;
});
}
else if (d.condition === 'greater_than') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && this.dateFormat(this.cellValue(item, d.field)) > d.value;
});
}
else if (d.condition === 'less_than') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) && this.dateFormat(this.cellValue(item, d.field)) < d.value;
});
}
}
// boolean filters
else if (d.type === 'bool') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) === d.value;
});
}
if (d.condition === 'is_null') {
rows = rows.filter((item) => {
return this.cellValue(item, d.field) == null || this.cellValue(item, d.field) === '';
});
d.value = '';
}
else if (d.condition === 'is_not_null') {
d.value = '';
rows = rows.filter((item) => {
return this.cellValue(item, d.field);
});
}
}
});
if (this.currentSearch && rows.length) {
let final = [];
const keys = (this.columns || [])
.filter((d) => d.search && !d.hide)
.map((d) => {
return d.field;
});
for (let j = 0; j < rows.length; j++) {
for (let i = 0; i < keys.length; i++) {
if (this.cellValue(rows[j], keys[i])?.toString().toLowerCase().includes(this.currentSearch.toLowerCase())) {
final.push(rows[j]);
break;
}
}
}
rows = final;
}
// sort rows
const collator = new Intl.Collator(undefined, {
numeric: true,
sensitivity: 'base',
});
const sortOrder = this.currentSortDirection === 'desc' ? -1 : 1;
rows.sort((a, b) => {
const valA = this.currentSortColumn?.split('.').reduce((obj, key) => obj?.[key], a);
const valB = this.currentSortColumn?.split('.').reduce((obj, key) => obj?.[key], b);
return collator.compare(valA, valB) * sortOrder;
});
this.filterRowCount = rows.length || 0;
result = rows.slice(this.offset() - 1, this.limit());
}
this.filterItems = result || [];
this.setPager();
}
// page change
movePage(page = 1) {
if (this.currentLoader || page < 1 || page > this.maxPage()) {
return;
}
this.currentPage = page;
this.clearSelectedRows();
if (this.isServerMode) {
this.changeForServer('page');
}
else {
this.filterRows();
this.pageChange.emit(this.currentPage);
}
}
// row update
changeRows() {
this.clearSelectedRows();
this.filterRows();
}
// pagesize changed
changePageSize() {
this.currentPage = 1;
this.clearSelectedRows();
if (this.isServerMode) {
this.changeForServer('pagesize', true);
}
else {
this.filterRows();
this.pageSizeChange.emit(this.currentPageSize);
}
}
// sorting
sortChangeMethod(field, dir = '') {
let direction = dir || 'asc';
if (field === this.currentSortColumn) {
if (this.currentSortDirection === 'asc') {
direction = 'desc';
}
}
const offset = (this.currentPage - 1) * this.currentPageSize;
const limit = this.currentPageSize;
this.currentSortColumn = field;
this.currentSortDirection = direction;
this.clearSelectedRows();
if (this.isServerMode) {
this.changeForServer('sort');
}
else {
this.filterRows();
this.sortChange.emit({ offset, limit, field, direction });
}
}
checkboxChange() {
this.checkIfAllSelected();
const rows = this.getSelectedRows();
this.rowSelect.emit(rows);
}
selectAll(checked, isAll = false) {
this.filterItems.map((d) => (d.selected = checked));
if (isAll) {
this.checkboxChange();
}
else {
this.checkIfAllSelected();
}
}
checkIfAllSelected() {
const cnt = this.filterItems.filter((d) => d.selected);
this.selectedAll = cnt.length && cnt.length === this.filterItems.length;
setTimeout(() => {
this.header1?.checkboxChange();
if (this.cloneHeaderInFooter) {
this.header2?.checkboxChange();
}
});
}
// columns filter
filterChangeMethod() {
this.currentPage = 1;
this.clearSelectedRows();
if (this.isServerMode) {
this.changeForServer('filter', true);
}
else {
this.filterRows();
this.filterChange.emit(this.columns);
}
}
// search
changeSearch() {
this.currentPage = 1;
this.clearSelectedRows();
if (this.isServerMode) {
this.changeForServer('search', true);
}
else {
this.filterRows();
this.searchChange.emit(this.currentSearch);
}
}
cellValue(item, field = '') {
return field?.split('.').reduce((obj, key) => obj?.[key], item);
}
dateFormat(date) {
try {
if (!date) {
return '';
}
const dt = new Date(date);
const day = dt.getDate();
const month = dt.getMonth() + 1;
const year = dt.getFullYear();
return year + '-' + (month > 9 ? month : '0' + month) + '-' + (day > 9 ? day : '0' + day);
}
catch { }
return '';
}
onRowClick(item, index) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
if (this.selectRowOnClick) {
if (this.isRowSelected(index)) {
this.unselectRow(index);
}
else {
this.selectRow(index);
}
this.checkboxChange();
}
this.rowClick.emit(item);
}, this.delay);
}
onRowDoubleClick(item) {
clearTimeout(this.timer);
this.rowDBClick.emit(item);
}
// emit change event for server side pagination
changeForServer(changeType, isResetPage = false) {
if (this.isServerMode) {
if (changeType === 'page') {
this.setPager();
}
this.setDefaultCondition();
const res = {
current_page: Number(isResetPage ? 1 : this.currentPage),
pagesize: Number(this.currentPageSize),
offset: Number((this.currentPage - 1) * this.currentPageSize),
sort_column: this.currentSortColumn,
sort_direction: this.currentSortDirection,
search: this.currentSearch,
column_filters: this.columns,
change_type: changeType,
};
this.changeServer.emit(res);
}
}
// set default conditions when values exists and condition empty
setDefaultCondition() {
for (let i = 0; i < this.columns.length; i++) {
let d = this.columns[i];
if (d.filter && ((d.value !== undefined && d.value !== null && d.value !== '') || d.condition === 'is_null' || d.condition === 'is_not_null')) {
if (d.type === 'string' && d.value && !d.condition) {
d.condition = 'contain';
}
if (d.type === 'number' && d.value && !d.condition) {
d.condition = 'equal';
}
if (d.type === 'date' && d.value && !d.condition) {
d.condition = 'equal';
}
}
}
}
// methods
reset() {
this.columns = this.noReact(this.oldColumns);
this.currentSearch = '';
this.currentPage = 1;
this.currentPageSize = this.oldPageSize;
this.currentSortColumn = this.oldSortColumn;
this.currentSortDirection = this.oldSortDirection;
this.clearSelectedRows();
if (this.isServerMode) {
this.changeForServer('reset', true);
}
else {
this.filterRows();
}
}
getSelectedRows() {
return this.filterItems.filter((d) => d.selected);
}
getColumnFilters() {
return this.columns;
}
clearSelectedRows() {
if (this.filterItems) {
this.selectAll(false);
}
}
selectRow(index) {
if (!this.isRowSelected(index)) {
const rows = this.filterItems.find((d, i) => i === index);
if (rows) {
rows.selected = true;
}
}
}
unselectRow(index) {
if (this.isRowSelected(index)) {
const rows = this.filterItems.find((d, i) => i === index);
rows.selected = false;
}
}
isRowSelected(index) {
const rows = this.filterItems.find((d, i) => i === index);
if (rows) {
return rows.selected;
}
return false;
}
// trackby
trackFilterItems(index, item) {
return this.uniqueKey ? item[this.uniqueKey] : (this.currentPage - 1) * this.pageSize + index;
}
ngAfterContentInit() {
this.slots.forEach((template) => {
const fieldName = template.fieldName;
if (fieldName) {
this.slotsMap.set(fieldName, template.templateRef);
}
});
}
hasSlot(fieldName = '') {
return this.slotsMap.has(fieldName);
}
getSlot(fieldName = '') {
return this.slotsMap.get(fieldName) || this.defaultTemplate;
}
// Sanitize and trust the HTML content
sanitizeHtml(html) {
return this.sanitizer.bypassSecurityTrustHtml(html);
}
noReact(value) {
return JSON.parse(JSON.stringify(value));
}
getRange(size) {
return Array.from({ length: size }, (_, index) => index + 1);
}
}
NgDataTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgDataTableComponent, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
NgDataTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NgDataTableComponent, selector: "ng-datatable", inputs: { loading: "loading", isServerMode: "isServerMode", skin: "skin", totalRows: "totalRows", rows: "rows", columns: "columns", hasCheckbox: "hasCheckbox", search: "search", page: "page", pageSize: "pageSize", pageSizeOptions: "pageSizeOptions", showPageSize: "showPageSize", rowClass: "rowClass", cellClass: "cellClass", sortable: "sortable", sortColumn: "sortColumn", sortDirection: "sortDirection", columnFilter: "columnFilter", pagination: "pagination", showNumbers: "showNumbers", showNumbersCount: "showNumbersCount", showFirstPage: "showFirstPage", showLastPage: "showLastPage", firstArrow: "firstArrow", lastArrow: "lastArrow", nextArrow: "nextArrow", previousArrow: "previousArrow", paginationInfo: "paginationInfo", noDataContent: "noDataContent", stickyHeader: "stickyHeader", height: "height", stickyFirstColumn: "stickyFirstColumn", cloneHeaderInFooter: "cloneHeaderInFooter", selectRowOnClick: "selectRowOnClick" }, outputs: { changeServer: "changeServer", sortChange: "sortChange", searchChange: "searchChange", pageChange: "pageChange", pageSizeChange: "pageSizeChange", rowSelect: "rowSelect", filterChange: "filterChange", rowClick: "rowClick", rowDBClick: "rowDBClick" }, queries: [{ propertyName: "slots", predicate: SlotDirective }], viewQueries: [{ propertyName: "header1", first: true, predicate: ["header1"], descendants: true }, { propertyName: "header2", first: true, predicate: ["header2"], descendants: true }, { propertyName: "defaultTemplate", first: true, predicate: ["defaultTemplate"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"bh-datatable bh-antialiased bh-relative bh-text-black bh-text-sm bh-font-normal\">\n <div class=\"bh-table-responsive\" [ngClass]=\"{'bh-min-h-[300px]': currentLoader }\" [style]=\"{ height: stickyHeader && height }\">\n <table [ngClass]=\"[skin]\">\n <thead [ngClass]=\"{ 'bh-sticky bh-top-0 bh-z-10': stickyHeader }\">\n <column-header\n #header1\n [all]=\"getProps\"\n [checkAll]=\"selectedAll\"\n (selectAll)=\"selectAll($event, true)\"\n (sortChange)=\"sortChangeMethod($event)\"\n (filterChange)=\"filterChangeMethod()\"\n ></column-header>\n </thead>\n\n <tbody>\n <ng-container *ngIf=\"filterRowCount\">\n <tr\n *ngFor=\"let item of filterItems; let i = index; trackBy:trackFilterItems.bind(this)\"\n [ngClass]=\"[(isFunction(rowClass) ? rowClass(item) : rowClass), selectRowOnClick? 'bh-cursor-pointer':'']\"\n (click)=\"onRowClick(item, i)\"\n (dblclick)=\"onRowDoubleClick(item)\"\n >\n <td *ngIf=\"hasCheckbox\" [ngClass]=\"{'bh-sticky bh-left-0 bh-bg-blue-light': stickyFirstColumn}\">\n <div class=\"bh-checkbox\" (click)=\"$event.stopPropagation();\">\n <input type=\"checkbox\" value=\"{{item[uniqueKey] ? item[uniqueKey] : i}}\" [(ngModel)]=\"item.selected\" (change)=\"checkboxChange();\" />\n <div>\n <icon-check class=\"check\"></icon-check>\n </div>\n </div>\n </td>\n <ng-container *ngFor=\"let col of columns; let j = index\">\n <td\n *ngIf=\"!col.hide\"\n [ngStyle]=\"{ 'width': col.width, 'min-width': col.minWidth, 'max-width': col.maxWidth }\"\n [ngClass]=\"[\n (isFunction(cellClass) ? cellClass(item) : cellClass),\n j === 0 && stickyFirstColumn ? 'bh-sticky bh-left-0 bh-bg-blue-light' : '',\n hasCheckbox && j === 0 && stickyFirstColumn ? 'bh-left-[52px]' : '',\n col.cellClass ? col.cellClass : ''\n ]\"\n >\n <ng-container *ngIf=\"hasSlot(col.field)\">\n <ng-container [ngTemplateOutlet]=\"getSlot(col.field)\" [ngTemplateOutletContext]=\"{ data: item }\"></ng-container>\n </ng-container>\n <div *ngIf=\"!hasSlot(col.field) && col.cellRenderer\" [innerHTML]=\"sanitizeHtml(col.cellRenderer(item))\"></div>\n <ng-container *ngIf=\"!hasSlot(col.field) && !col.cellRenderer\"> {{ cellValue(item, col.field) }} </ng-container>\n </td>\n </ng-container>\n </tr>\n </ng-container>\n <tr *ngIf=\"!filterRowCount && !currentLoader\">\n <td [attr.colspan]=\"columns.length + 1\">{{ noDataContent }}</td>\n </tr>\n\n <ng-container *ngIf=\"!filterRowCount && currentLoader\">\n <tr *ngFor=\"let k of getRange(pageSize)\" class=\"!bh-bg-white bh-h-11 !bh-border-transparent\">\n <td [attr.colspan]=\"columns.length + 1\" class=\"!bh-p-0 !bh-border-transparent\">\n <div class=\"bh-skeleton-box bh-h-8\"></div>\n </td>\n </tr>\n </ng-container>\n </tbody>\n\n <tfoot *ngIf=\"cloneHeaderInFooter\" [ngClass]=\"{ 'bh-sticky bh-bottom-0': stickyHeader }\">\n <column-header\n #header2\n [all]=\"getProps\"\n [isFooter]=\"true\"\n [checkAll]=\"selectedAll\"\n (selectAll)=\"selectAll($event)\"\n (sortChange)=\"sortChangeMethod($event)\"\n (filterChange)=\"filterChangeMethod()\"\n ></column-header>\n </tfoot>\n </table>\n\n <div *ngIf=\"filterRowCount && currentLoader\" class=\"bh-absolute bh-inset-0 bh-bg-blue-light/50 bh-grid bh-place-content-center\">\n <icon-loader></icon-loader>\n </div>\n </div>\n\n <div *ngIf=\"pagination && filterRowCount\" class=\"bh-pagination bh-py-5\">\n <div class=\"bh-flex bh-items-center bh-flex-wrap bh-flex-col sm:bh-flex-row bh-gap-4\">\n <div class=\"bh-pagination-info bh-flex bh-items-center\">\n <span class=\"bh-mr-2\"> {{ pager.stringFormat }} </span>\n <select *ngIf=\"showPageSize\" [(ngModel)]=\"currentPageSize\" class=\"bh-pagesize\" (ngModelChange)=\"changePageSize()\">\n <option *ngFor=\"let option of pageSizeOptions\" [value]=\"option\">{{ option }}</option>\n </select>\n </div>\n\n <div class=\"bh-pagination-number sm:bh-ml-auto bh-inline-flex bh-items-center bh-space-x-1\">\n <button *ngIf=\"showFirstPage\" type=\"button\" class=\"bh-page-item first-page\" [class.disabled]=\"currentPage <= 1\" (click)=\"movePage(1)\">\n <span *ngIf=\"firstArrow\" [innerHTML]=\"sanitizeHtml(firstArrow)\"></span>\n <svg *ngIf=\"!firstArrow\" aria-hidden=\"true\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\">\n <g fill=\"currentColor\" fill-rule=\"evenodd\">\n <path d=\"M8.354 1.646a.5.5 0 0 1 0 .708L2.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\" />\n <path d=\"M12.354 1.646a.5.5 0 0 1 0 .708L6.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\" />\n </g>\n </svg>\n </button>\n <button type=\"button\" class=\"bh-page-item previous-page\" [class.disabled]=\"currentPage <= 1\" (click)=\"movePage(currentPage - 1)\">\n <span *ngIf=\"previousArrow\" [innerHTML]=\"sanitizeHtml(previousArrow)\"></span>\n <svg *ngIf=\"!previousArrow\" aria-hidden=\"true\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\">\n <path\n fill=\"currentColor\"\n fill-rule=\"evenodd\"\n d=\"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z\"\n />\n </svg>\n </button>\n\n <ng-container *ngIf=\"showNumbers\">\n <button\n *ngFor=\"let page of pager.pages\"\n type=\"button\"\n class=\"bh-page-item\"\n [class.disabled]=\"currentPage === page\"\n [class.bh-active]=\"page === currentPage\"\n (click)=\"movePage(page)\"\n >\n {{ page }}\n </button>\n </ng-container>\n\n <button type=\"button\" class=\"bh-page-item next-page\" [class.disabled]=\"currentPage >= maxPage()\" (click)=\"movePage(currentPage + 1)\">\n <span *ngIf=\"nextArrow\" [innerHTML]=\"sanitizeHtml(nextArrow)\"> </span>\n <svg *ngIf=\"!nextArrow\" aria-hidden=\"true\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\">\n <path\n fill=\"currentColor\"\n fill-rule=\"evenodd\"\n d=\"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8L4.646 2.354a.5.5 0 0 1 0-.708z\"\n />\n </svg>\n </button>\n\n <button *ngIf=\"showLastPage\" type=\"button\" class=\"bh-page-item last-page\" [class.disabled]=\"currentPage >= maxPage()\" (click)=\"movePage(maxPage())\">\n <span *ngIf=\"lastArrow\" [innerHTML]=\"sanitizeHtml(lastArrow)\"> </span>\n <svg *ngIf=\"!lastArrow\" aria-hidden=\"true\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\">\n <g fill=\"currentColor\" fill-rule=\"evenodd\">\n <path d=\"M3.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L9.293 8L3.646 2.354a.5.5 0 0 1 0-.708z\" />\n <path d=\"M7.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L13.293 8L7.646 2.354a.5.5 0 0 1 0-.708z\" />\n </g>\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n", styles: ["*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }*,:after,:before{border:0 solid #0000;box-sizing:border-box}.bh-datatable .bh-table-responsive{position:relative;width:100%;overflow:auto;border-radius:.25rem}.bh-datatable .bh-table-responsive table{width:100%;max-width:100%;border-collapse:collapse!important}.bh-datatable .bh-table-responsive table tfoot tr,.bh-datatable .bh-table-responsive table thead tr{--tw-bg-opacity:1;background-color:rgb(246 247 250/var(--tw-bg-opacity))}.bh-datatable .bh-table-responsive table tbody tr td,.bh-datatable .bh-table-responsive table tfoot tr th,.bh-datatable .bh-table-responsive table thead tr th{padding:.75rem 1rem;text-align:left}.bh-datatable .bh-table-responsive table tfoot tr th,.bh-datatable .bh-table-responsive table thead tr th{vertical-align:top;font-weight:700}.bh-datatable .bh-table-responsive table tbody tr{border-bottom-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(246 247 250/var(--tw-border-opacity))}.bh-datatable .bh-table-responsive table.bh-table-striped tbody tr:nth-child(odd){background-color:#e0e6ed26}.bh-datatable .bh-table-responsive table.bh-table-hover tbody tr:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bh-datatable .bh-table-responsive table.bh-table-compact tbody tr td,.bh-datatable .bh-table-responsive table.bh-table-compact thead tr th{padding:.5rem .75rem}.bh-datatable .bh-table-responsive table.bh-table-bordered tbody tr td,.bh-datatable .bh-table-responsive table.bh-table-bordered thead tr th{border-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(246 247 250/var(--tw-border-opacity))}.bh-datatable .bh-pagination .bh-page-item{display:grid;height:2rem;width:2rem;cursor:pointer;-webkit-user-select:none;user-select:none;place-content:center;border-radius:9999px;border:1px solid #0e17264d;--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));padding:.375rem .625rem;--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity));outline-width:0}.bh-datatable .bh-pagination .bh-page-item:hover{--tw-border-opacity:1;border-color:rgb(67 97 238/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(67 97 238/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.bh-datatable .bh-pagination .bh-page-item{-webkit-appearance:button;background-image:none}.bh-datatable .bh-pagination .bh-page-item.disabled:not(.bh-active){pointer-events:none;opacity:.5}.bh-datatable .bh-pagination .bh-page-item.bh-active{--tw-border-opacity:1;border-color:rgb(67 97 238/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(67 97 238/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.bh-datatable .bh-table-responsive button,.bh-datatable .bh-table-responsive input{outline:2px solid #0000;outline-offset:2px}.bh-datatable .bh-pagination-info .bh-pagesize{box-sizing:border-box;border-radius:.25rem;border-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(224 230 237/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));padding:.375rem .5rem;font-weight:400;--tw-text-opacity:1;color:rgb(14 23 38/var(--tw-text-opacity));outline-width:0}.bh-datatable .bh-pagination-info .bh-pagesize:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-color:#e0e6ed66}.bh-datatable .bh-table-responsive table th .bh-filter{margin-top:.125rem;display:flex;height:30px;width:100%;align-items:center}.bh-datatable .bh-table-responsive table th .bh-filter>.bh-form-control{box-sizing:border-box;height:100%;width:100%;min-width:60px;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(224 230 237/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));padding:.25rem .75rem;font-size:.875rem;line-height:1.25rem;font-weight:400;--tw-text-opacity:1;color:rgb(14 23 38/var(--tw-text-opacity));outline-width:0}.bh-datatable .bh-table-responsive table th .bh-filter>.bh-form-control:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-color:#e0e6ed66}.bh-datatable .bh-table-responsive table th .bh-filter>select{border-radius:.25rem}.bh-datatable .bh-table-responsive table th .bh-filter>button{display:grid;height:30px;width:30px;flex-shrink:0;cursor:pointer;place-content:center;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(224 230 237/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(224 230 237/var(--tw-bg-opacity));color:#0e1726b3}.bh-datatable .bh-table-responsive table th .bh-filter>button:hover{color:#0e1726e6}.bh-datatable .bh-table-responsive table th .bh-filter>button{-webkit-appearance:button;background-image:none}.bh-datatable .bh-filter-menu button{display:flex;width:100%;cursor:pointer;border:1px solid #0000;--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));padding:.375rem 1rem;text-align:left}.bh-datatable .bh-filter-menu button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity));font-weight:700}.bh-datatable .bh-filter-menu button{-webkit-appearance:button;background-image:none}.bh-datatable .bh-filter-menu button.active{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity));font-weight:700}.bh-datatable .bh-table-responsive input[type=checkbox]{position:absolute;height:1.25rem;width:1.25rem;opacity:0}.bh-datatable .bh-table-responsive input[type=checkbox]+div{display:grid;height:1.25rem;width:1.25rem;place-content:center;border-radius:.25rem;border-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(224 230 237/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bh-datatable .bh-table-responsive input[type=checkbox]+div svg{pointer-events:none;display:none;height:.75rem;width:.75rem;fill:currentColor;--tw-text-opacity:1;color:rgb(67 97 238/var(--tw-text-opacity))}.bh-datatable .bh-table-responsive input[type=checkbox]:checked+div,.bh-datatable .bh-table-responsive input[type=checkbox]:indeterminate+div{--tw-border-opacity:1;border-color:rgb(67 97 238/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(67 97 238/var(--tw-bg-opacity))}.bh-datatable .bh-table-responsive input[type=checkbox]:checked+div svg.check,.bh-datatable .bh-table-responsive input[type=checkbox]:indeterminate+div svg.intermediate{display:flex;--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.bh-absolute{position:absolute}.bh-relative{position:relative}.bh-sticky{position:sticky}.bh-inset-0{top:0;right:0;left:0}.bh-bottom-0,.bh-inset-0{bottom:0}.bh-left-0{left:0}.bh-left-\\[52px\\]{left:52px}.bh-right-0{right:0}.bh-top-0{top:0}.bh-top-full{top:100%}.bh-z-10{z-index:10}.bh-z-\\[1\\]{z-index:1}.bh-mb-2{margin-bottom:.5rem}.bh-ml-3{margin-left:.75rem}.bh-mr-2{margin-right:.5rem}.bh-mt-1{margin-top:.25rem}.bh-flex{display:flex}.bh-inline-flex{display:inline-flex}.bh-grid{display:grid}.bh-hidden{display:none}.bh-h-11{height:2.75rem}.bh-h-8{height:2rem}.bh-min-h-\\[300px\\]{min-height:300px}.bh-w-32{width:8rem}.bh-w-4{width:1rem}.bh-w-px{width:1px}.bh-cursor-pointer{cursor:pointer}.bh-select-none{-webkit-user-select:none;user-select:none}.bh-flex-col{flex-direction:column}.bh-flex-wrap{flex-wrap:wrap}.bh-place-content-center{place-content:center}.bh-items-center{align-items:center}.bh-gap-4{gap:1rem}.bh-space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.25rem*var(--tw-space-x-reverse));margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)))}.bh-overflow-hidden{overflow:hidden}.bh-rounded{border-radius:.25rem}.bh-rounded-md{border-radius:.375rem}.bh-border{border-width:1px}.bh-border-solid{border-style:solid}.\\!bh-border-transparent{border-color:#0000!important}.bh-border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.bh-border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.\\!bh-bg-white{--tw-bg-opacity:1!important;background-color:rgb(255 255 255/var(--tw-bg-opacity))!important}.bh-bg-blue-light{--tw-bg-opacity:1;background-color:rgb(246 247 250/var(--tw-bg-opacity))}.bh-bg-blue-light\\/50{background-color:#f6f7fa80}.bh-bg-gray-200{background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bh-bg-gray-200,.bh-bg-white{--tw-bg-opacity:1}.bh-bg-white{background-color:rgb(255 255 255/var(--tw-bg-opacity))}.\\!bh-p-0{padding:0!important}.bh-p-10{padding:2.5rem}.bh-p-2{padding:.5rem}.bh-py-5{padding-top:1.25rem;padding-bottom:1.25rem}.bh-text-\\[13px\\]{font-size:13px}.bh-text-sm{font-size:.875rem;line-height:1.25rem}.bh-font-normal{font-weight:400}.\\!bh-text-primary{--tw-text-opacity:1!important;color:rgb(67 97 238/var(--tw-text-opacity))!important}.bh-text-black{--tw-text-opacity:1;color:rgb(14 23 38/var(--tw-text-opacity))}.bh-text-black\\/20{color:#0e172633}.bh-text-primary{--tw-text-opacity:1;color:rgb(67 97 238/var(--tw-text-opacity))}.bh-antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.bh-shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.bh-outline-0{outline-width:0}.bh-filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.bh-skeleton-box{position:relative;width:100%;overflow:hidden;--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bh-skeleton-box:after{position:absolute;inset:0;--tw-translate-x:-100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));animation:bhshimmer 2s infinite;background-image:linear-gradient(90deg,#0000,rgba(0,0,0,.025) 20%,#0000000d 50%,#0000);--tw-content:\"\";content:var(--tw-content)}@keyframes bhshimmer{to{transform:translate(100%)}}.hover\\:bh-opacity-80:hover{opacity:.8}.focus\\:bh-border-gray-200:focus{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}@media (min-width:640px){.sm\\:bh-ml-auto{margin-left:auto}.sm\\:bh-flex-row{flex-direction:row}}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy