UNPKG

@alfiob/ng-datatable

Version:

ng-datatable - fully customizable & easy to use datatable library

668 lines 162 kB
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