UNPKG

dynamic-mat-table

Version:

dynamic-mat-table is an Angular component for presenting large and complex data with a lightning fast performance (at least 10x faster) and excellent level of control over the presentation.

680 lines 118 kB
import { Component, QueryList, ElementRef, ViewChild, TemplateRef, Renderer2, ChangeDetectorRef, Input, ContentChildren, Injector, HostBinding, ChangeDetectionStrategy, } from '@angular/core'; import { TableCoreDirective } from '../cores/table.core.directive'; import { TableService } from './dynamic-mat-table.service'; import { HeaderFilterComponent } from './extensions/filter/header-filter.component'; import { MatDialog } from '@angular/material/dialog'; import { trigger, transition, style, animate, query, stagger, state, } from '@angular/animations'; import { ResizeColumn } from '../models/resize-column.mode'; import { TableIntl } from '../international/table-Intl'; import { moveItemInArray, } from '@angular/cdk/drag-drop'; import { isNullorUndefined } from '../cores/type'; import { TableSetting } from '../models/table-setting.model'; import { delay, filter } from 'rxjs/operators'; import { MatMenuTrigger } from '@angular/material/menu'; import { Overlay, OverlayContainer, OverlayPositionBuilder, } from '@angular/cdk/overlay'; import { requestFullscreen } from '../utilizes/html.helper'; import { TooltipComponent } from '../tooltip/tooltip.component'; import { ComponentPortal } from '@angular/cdk/portal'; export const tableAnimation = trigger("tableAnimation", [ transition("void => *", [ query(":enter", style({ transform: "translateX(-50%)", opacity: 0 }), { //limit: 5, optional: true, }), query(":enter", stagger("0.01s", [ animate("0.5s ease", style({ transform: "translateX(0%)", opacity: 1 })), ]), { //limit: 5, optional: true, }), ]), ]); export const expandAnimation = trigger("detailExpand", [ state("collapsed", style({ height: "0px", minHeight: "0" })), state("expanded", style({ height: "*" })), transition("expanded <=> collapsed", animate("100ms cubic-bezier(0.4, 0.0, 0.2, 1)")), ]); export class DynamicMatTableComponent extends TableCoreDirective { constructor(dialog, renderer, languagePack, tableService, cdr, overlay, overlayContainer, overlayPositionBuilder, config) { super(tableService, cdr, config); this.dialog = dialog; this.renderer = renderer; this.languagePack = languagePack; this.tableService = tableService; this.cdr = cdr; this.overlay = overlay; this.overlayContainer = overlayContainer; this.overlayPositionBuilder = overlayPositionBuilder; this.config = config; this.init = false; this.height = null; this.contextMenuPosition = { x: "0px", y: "0px" }; this.dragDropData = { dragColumnIndex: -1, dropColumnIndex: -1 }; this.printing = true; this.printTemplate = null; this.resizeColumn = new ResizeColumn(); /* Tooltip */ this.overlayRef = null; this.indexTrackFn = (index) => { return index; }; this.currentContextMenuSender = {}; this.overlayContainer .getContainerElement() .addEventListener("contextmenu", (e) => { e.preventDefault(); return false; }); this.eventsSubscription = this.resizeColumn.widthUpdate .pipe(delay(150), filter((data) => data.e.columnIndex >= 0) /* Checkbox Column */) .subscribe((data) => { var _a; let i = data.e.columnIndex; if (data.e.resizeHandler === "left") { const visibleColumns = this.columns.filter((c) => c.display !== "hidden" && c.index < data.e.columnIndex); i = visibleColumns[visibleColumns.length - 1].index; } // this.columns[i].width = data.w; const unit = this.columns[i].widthUnit || "px"; let style = ""; if (this.columns[i].minWidth) { data.w = Math.min(this.columns[i].minWidth, data.w); } if (unit === "px") { style = data.w + "px"; } else if (unit === "%") { const widthChanges = ((_a = this.tableSetting.columnSetting[i].width) !== null && _a !== void 0 ? _a : 0) - data.w; console.log(this.tableSetting.columnSetting[i].width, data.w, widthChanges); style = `calc( ${this.columns[i].widthPercentage}% + ${widthChanges}px)`; } this.columns[i].style = Object.assign(Object.assign({}, this.columns[i].style), { "max-width": style, "min-width": style }); /* store latest width in setting if exists */ if (this.tableSetting.columnSetting[i]) { this.tableSetting.columnSetting[i].width = data.w; } this.refreshGrid(); }); } get setting() { return this.tableSetting; } set setting(value) { var _a; if (!isNullorUndefined(value)) { value.alternativeRowStyle = value.alternativeRowStyle || this.tableSetting.alternativeRowStyle; value.columnSetting = value.columnSetting || this.tableSetting.columnSetting; value.direction = value.direction || this.tableSetting.direction; value.normalRowStyle = value.normalRowStyle || this.tableSetting.normalRowStyle; value.visibleActionMenu = value.visibleActionMenu || this.tableSetting.visibleActionMenu; value.visibleTableMenu = value.visibleTableMenu || this.tableSetting.visibleTableMenu; value.autoHeight = value.autoHeight || this.tableSetting.autoHeight; value.saveSettingMode = value.saveSettingMode || this.tableSetting.saveSettingMode || "simple"; this.pagination.pageSize = value.pageSize || this.tableSetting.pageSize || this.pagination.pageSize; /* Dynamic Cell must update when setting change */ (_a = value === null || value === void 0 ? void 0 : value.columnSetting) === null || _a === void 0 ? void 0 : _a.forEach((column) => { var _a; const originalColumn = (_a = this.columns) === null || _a === void 0 ? void 0 : _a.find((c) => c.name === column.name); if (originalColumn) { column = Object.assign(Object.assign({}, originalColumn), column); } }); this.tableSetting = value; this.setDisplayedColumns(); } } ngAfterViewInit() { this.tvsDataSource.paginator = this.paginator; this.tvsDataSource.sort = this.sort; this.dataSource.subscribe((x) => { x = x || []; this.rowSelectionModel.clear(); this.tvsDataSource.data = []; this.initSystemField(x); this.tvsDataSource.data = x; // this.cdr.detectChanges(); this.refreshUI(); // window.requestAnimationFrame(() => { // }); }); this.tvsDataSource.sort.sortChange.subscribe((sort) => { this.pagination.pageIndex = 0; this.onTableEvent.emit({ event: "SortChanged", sender: sort }); }); } tooltip_onChanged(column, row, elementRef, show) { if (column.cellTooltipEnable === true) { if (show === true && row[column.name]) { if (this.overlayRef !== null) { this.closeTooltip(); } const positionStrategy = this.overlayPositionBuilder .flexibleConnectedTo(elementRef) .withPositions([ { originX: "center", originY: "top", overlayX: "center", overlayY: "bottom", offsetY: -8, }, ]); this.overlayRef = this.overlay.create({ positionStrategy }); const option = { providers: [{ provide: "tooltipConfig", useValue: row[column.name], }], }; const injector = Injector.create(option); const tooltipRef = this.overlayRef.attach(new ComponentPortal(TooltipComponent, null, injector)); setTimeout(() => { tooltipRef.destroy(); }, 5000); } else if (show === false && this.overlayRef !== null) { this.closeTooltip(); } } } closeTooltip() { var _a; (_a = this.overlayRef) === null || _a === void 0 ? void 0 : _a.detach(); this.overlayRef = null; } ellipsis(column, cell = true) { if (cell === true && column.cellEllipsisRow > 0) { return { display: "-webkit-box", "-webkit-line-clamp": column === null || column === void 0 ? void 0 : column.cellEllipsisRow, "-webkit-box-orient": "vertical", overflow: "hidden", "white-space": "pre-wrap", }; } else if (cell === true && column.headerEllipsisRow > 0) { return { display: "-webkit-box", "-webkit-line-clamp": column === null || column === void 0 ? void 0 : column.headerEllipsisRow, "-webkit-box-orient": "vertical", overflow: "hidden", "white-space": "pre-wrap", }; } } trackColumn(index, item) { return `${item.index}`; } ngOnDestroy() { if (this.eventsSubscription) { this.eventsSubscription.unsubscribe(); } } refreshUI() { var _a, _b; if (this.tableSetting.autoHeight === true) { this.height = this.autoHeight(); } else { this.height = null; } this.refreshColumn(this.tableColumns); this.tvsDataSource.columns = this.columns; const scrollStrategy = this.viewport["_scrollStrategy"]; (_a = scrollStrategy === null || scrollStrategy === void 0 ? void 0 : scrollStrategy.viewport) === null || _a === void 0 ? void 0 : _a.checkViewportSize(); (_b = scrollStrategy === null || scrollStrategy === void 0 ? void 0 : scrollStrategy.viewport) === null || _b === void 0 ? void 0 : _b.scrollToOffset(0); this.cdr.detectChanges(); } ngOnInit() { setTimeout(() => { this.init = true; }, 1000); const scrollStrategy = this.viewport["_scrollStrategy"]; scrollStrategy.offsetChange.subscribe((offset) => { }); this.viewport.renderedRangeStream.subscribe((t) => { // in expanding row scrolling make not good appearance therefor close it. if (this.expandedElement && this.expandedElement.option && this.expandedElement.option.expand) { // this.expandedElement.option.expand = false; // this.expandedElement = null; } }); } get inverseOfTranslation() { if (!this.viewport || !this.viewport["_renderedContentOffset"]) { return -0; } let offset = this.viewport["_renderedContentOffset"]; return -offset; } headerClass(column) { return column === null || column === void 0 ? void 0 : column.classNames; } rowStyle(row) { var _a; let style = ((_a = row === null || row === void 0 ? void 0 : row.option) === null || _a === void 0 ? void 0 : _a.style) || {}; if (this.setting.alternativeRowStyle && row.id % 2 === 0) { // style is high priority style = Object.assign(Object.assign({}, this.setting.alternativeRowStyle), style); } if (this.setting.rowStyle) { style = Object.assign(Object.assign({}, this.setting.rowStyle), style); } return style; } cellClass(option, column) { let className = null; if (option && column.name) { className = option[column.name] ? option[column.name].style : null; } if (className === null) { return column.cellClass; } else { return Object.assign(Object.assign({}, className), column.cellClass); } } cellStyle(option, column) { let style = null; if (option && column.name) { style = option[column.name] ? option[column.name].style : null; } /* consider to column width resize */ if (style === null) { return Object.assign(Object.assign({}, column.cellStyle), column.style); } else { return Object.assign(Object.assign(Object.assign({}, style), column.cellStyle), column === null || column === void 0 ? void 0 : column.style); } } cellIcon(option, cellName) { if (option && cellName) { return option[cellName] ? option[cellName].icon : null; } else { return null; } } filter_onChanged(column, filter) { this.pending = true; this.tvsDataSource.setFilter(column.name, filter).subscribe(() => { this.clearSelection(); this.pending = false; }); } onContextMenu(event, column, row) { var _a, _b; if (((_a = this.currentContextMenuSender) === null || _a === void 0 ? void 0 : _a.time) && new Date().getTime() - this.currentContextMenuSender.time < 500) { return; } this.contextMenu.closeMenu(); if (((_b = this.contextMenuItems) === null || _b === void 0 ? void 0 : _b.length) === 0) { return; } event.preventDefault(); this.contextMenuPosition.x = event.clientX + "px"; this.contextMenuPosition.y = event.clientY + "px"; this.currentContextMenuSender = { column: column, row: row, time: new Date().getTime(), }; this.contextMenu.menuData = this.currentContextMenuSender; this.contextMenu.menu.focusFirstItem("mouse"); this.onRowEvent.emit({ event: "BeforeContextMenuOpen", sender: { row: row, column: column, contextMenu: this.contextMenuItems }, }); this.contextMenu.openMenu(); } onContextMenuItemClick(data) { this.contextMenu.menuData.item = data; this.onRowEvent.emit({ event: "ContextMenuClick", sender: this.contextMenu.menuData, }); } tableMenuActionChange(e) { var _a; if (e.type === "TableSetting") { this.settingChange.emit({ type: 'apply', setting: this.tableSetting }); this.refreshColumn(this.tableSetting.columnSetting); } else if (e.type === "DefaultSetting") { (this.setting.settingList || []).forEach((setting) => { if (setting.settingName === e.data) { setting.isDefaultSetting = true; } else { setting.isDefaultSetting = false; } }); this.settingChange.emit({ type: 'default', setting: this.tableSetting }); } else if (e.type === "SaveSetting") { const newSetting = Object.assign({}, this.setting); delete newSetting.settingList; newSetting.settingName = e.data; const settingIndex = (this.setting.settingList || []).findIndex((f) => f.settingName === e.data); if (settingIndex === -1) { this.setting.settingList.push(JSON.parse(JSON.stringify(newSetting))); this.settingChange.emit({ type: 'create', setting: this.tableSetting }); } else { this.setting.settingList[settingIndex] = JSON.parse(JSON.stringify(newSetting)); this.settingChange.emit({ type: 'save', setting: this.tableSetting }); } } else if (e.type === "DeleteSetting") { this.setting.settingList = this.setting.settingList.filter((s) => s.settingName !== e.data.settingName); this.setting.columnSetting.filter(f => f.display === 'hidden').forEach(f => f.display = 'visible'); this.refreshColumn(this.setting.columnSetting); this.settingChange.emit({ type: 'delete', setting: this.tableSetting }); } else if (e.type === "SelectSetting") { if (e.data != null) { let setting = null; this.setting.settingList.forEach((s) => { if (s.settingName === e.data) { s.isCurrentSetting = true; setting = Object.assign({}, this.setting.settingList.find((s) => s.settingName === e.data)); } else { s.isCurrentSetting = false; } }); setting.settingList = this.setting.settingList; delete setting.isCurrentSetting; delete setting.isDefaultSetting; if (this.pagingMode !== 'none' && this.pagination.pageSize != (setting === null || setting === void 0 ? void 0 : setting.pageSize)) { this.pagination.pageSize = (setting === null || setting === void 0 ? void 0 : setting.pageSize) || this.pagination.pageSize; this.paginationChange.emit(this.pagination); } /* Dynamic Cell must update when setting change */ (_a = setting.columnSetting) === null || _a === void 0 ? void 0 : _a.forEach((column) => { const originalColumn = this.columns.find((c) => c.name === column.name); column = Object.assign(Object.assign({}, originalColumn), column); }); this.tableSetting = setting; this.refreshColumn(this.setting.columnSetting); this.settingChange.emit({ type: 'select', setting: this.tableSetting }); } else { const columns = []; this.columns.forEach(c => { columns.push(Object.assign({}, c)); }); this.refreshColumn(columns); this.refreshUI(); } } else if (e.type === "FullScreenMode") { requestFullscreen(this.tbl.elementRef); } else if (e.type === "Download") { this.onTableEvent.emit({ event: 'ExportData', sender: { type: e.data, columns: this.columns, data: this.tvsDataSource.filteredData, dataSelection: this.rowSelectionModel } }); // if (e.data === "CSV") // { // this.tableService.exportToCsv<T>( // this.columns, // this.tvsDataSource.filteredData, // this.rowSelectionModel // ); // } else if (e.data === "JSON") // { // this.tableService.exportToJson(this.tvsDataSource.filteredData); // } } else if (e.type === "FilterClear") { this.tvsDataSource.clearFilter(); this.headerFilterList.forEach((hf) => hf.clearColumn_OnClick()); } else if (e.type === "Print") { this.onTableEvent.emit({ event: 'ExportData', sender: { type: 'Print', columns: this.columns, data: this.tvsDataSource.filteredData, dataSelection: this.rowSelectionModel } }); // this.printConfig.title = this.printConfig.title || this.tableName; // this.printConfig.direction = this.tableSetting.direction || "ltr"; // debugger // this.printConfig.columns = this.tableColumns.filter(t => t.display !== 'hidden' && t.printable !== false); // this.printConfig.displayedFields = this.printConfig.columns.map((o) => o.name); // this.printConfig.data = this.tvsDataSource.filteredData; // const params = this.tvsDataSource.toTranslate(); // this.printConfig.tablePrintParameters = []; // params.forEach((item) => // { // this.printConfig.tablePrintParameters.push(item); // }); // this.dialog.open(PrintTableDialogComponent, { // width: "90vw", // data: this.printConfig, // }); } } rowMenuActionChange(contextMenuItem, row) { this.onRowEvent.emit({ event: "RowActionMenu", sender: { row: row, action: contextMenuItem }, }); // this.rowActionMenuChange.emit({actionItem: contextMenuItem, rowItem: row }); } pagination_onChange(e) { if (this.pagingMode !== "none") { this.pending = true; this.tvsDataSource.refreshFilterPredicate(); this.pagination.length = e.length; this.pagination.pageIndex = e.pageIndex; this.pagination.pageSize = e.pageSize; this.setting.pageSize = e.pageSize; /* Save Page Size when need in setting config */ this.paginationChange.emit(this.pagination); } } autoHeight() { const minHeight = this.headerHeight + (this.rowHeight + 1) * this.dataSource.value.length + this.footerHeight * 0; return minHeight.toString(); } reload_onClick() { this.onTableEvent.emit({ sender: null, event: "ReloadData" }); } ///////////////////////////////////////////////////////////////// onResizeColumn(event, index, type) { this.resizeColumn.resizeHandler = type; this.resizeColumn.startX = event.pageX; if (this.resizeColumn.resizeHandler === "right") { this.resizeColumn.startWidth = event.target.parentElement.clientWidth; this.resizeColumn.columnIndex = index; } else { if (event.target.parentElement.previousElementSibling === null) { /* for first column not resize */ return; } else { this.resizeColumn.startWidth = event.target.parentElement.previousElementSibling.clientWidth; this.resizeColumn.columnIndex = index; } } event.preventDefault(); this.mouseMove(index); } mouseMove(index) { this.resizableMousemove = this.renderer.listen("document", "mousemove", (event) => { if (this.resizeColumn.resizeHandler !== null && event.buttons) { const rtl = this.direction === "rtl" ? -1 : 1; let width = 0; if (this.resizeColumn.resizeHandler === "right") { const dx = event.pageX - this.resizeColumn.startX; width = this.resizeColumn.startWidth + rtl * dx; } else { const dx = this.resizeColumn.startX - event.pageX; width = this.resizeColumn.startWidth - rtl * dx; } if (this.resizeColumn.columnIndex === index && width > this.minWidth) { // this.resizeColumn.columnIndex = index; this.resizeColumn.widthUpdate.next({ e: this.resizeColumn, w: width, }); } } }); this.resizableMouseup = this.renderer.listen("document", "mouseup", (event) => { if (this.resizeColumn.resizeHandler !== null) { this.resizeColumn.resizeHandler = null; this.resizeColumn.columnIndex = -1; /* fix issue sticky column */ this.table.updateStickyColumnStyles(); /* Remove Event Listen */ this.resizableMousemove(); } }); } expandRow(rowIndex, mode = true) { if (rowIndex === null || rowIndex === undefined) { throw "Row index is not defined."; } if (this.expandedElement === this.tvsDataSource.allData[rowIndex]) { this.expandedElement.option.expand = mode; this.expandedElement = this.expandedElement === this.tvsDataSource.allData[rowIndex] ? null : this.tvsDataSource.allData[rowIndex]; } else { if (this.expandedElement && this.expandedElement !== this.tvsDataSource.allData[rowIndex]) { this.expandedElement.option.expand = false; } this.expandedElement = null; if (mode === true) { this.expandedElement = this.expandedElement === this.tvsDataSource.allData[rowIndex] ? null : this.tvsDataSource.allData[rowIndex]; if (this.expandedElement.option === undefined || this.expandedElement.option === null) { this.expandedElement.option = { expand: false }; } this.expandedElement.option.expand = true; } } } onRowSelection(e, row, column) { if (this.rowSelectionMode && this.rowSelectionMode !== "none" && column.rowSelectable !== false) { this.onRowSelectionChange(e, row); } } onCellClick(e, row, column) { if (column.cellTooltipEnable === true) { this.closeTooltip(); /* Fixed BUG: Open Overlay when redirect to other route */ } this.onRowSelection(e, row, column); if (column.clickable !== false && (column.clickType === null || column.clickType === "cell")) { this.onRowEvent.emit({ event: "CellClick", sender: { row: row, column: column }, }); } } onLabelClick(e, row, column) { if (column.clickable !== false && column.clickType === "label") { this.onRowEvent.emit({ event: "LabelClick", sender: { row: row, column: column, e: e }, }); } } onRowDblClick(e, row) { this.onRowEvent.emit({ event: "DoubleClick", sender: { row: row, e: e } }); } onRowClick(e, row) { this.onRowEvent.emit({ event: "RowClick", sender: { row: row, e: e } }); } /************************************ Drag & Drop Column *******************************************/ dragStarted(event) { // this.dragDropData.dragColumnIndex = event.source.; } dropListDropped(event) { if (event) { this.dragDropData.dropColumnIndex = event.currentIndex; this.moveColumn(event.previousIndex, event.currentIndex); } } drop(event) { moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); // updates moved data and table, but not dynamic if more dropzones // this.dataSource.data = clonedeep(this.dataSource.data); } /************************************ *******************************************/ copyProperty(from, to) { const keys = Object.keys(from); keys.forEach((key) => { if (from[key] !== undefined && from[key] === null) { to[key] = Array.isArray(from[key]) ? Object.assign([], from[key]) : Object.assign({}, from[key]); } }); } } /** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */ DynamicMatTableComponent.decorators = [ { type: Component, args: [{ selector: "dynamic-mat-table", template: "<cdk-virtual-scroll-viewport #tbl [ngClass]=\"viewportClass\" [tvsItemSize]=\"rowHeight || 48\"\r\n [headerHeight]=\"headerHeight || 56\" [footerHeight]=\"headerHeight || 56\" [headerEnabled]=\"headerEnable || true\"\r\n [footerEnabled]=\"footerEnable || false\" [ngStyle]=\"{'background-color': backgroundColor || 'white'}\"\r\n [class.print-preview]=\"printing\">\r\n\r\n <mat-table matSort class=\"dynamic-table\" multiTemplateDataRows [cdkDropListDisabled]=\"false\" cdkDropList\r\n cdkDropListOrientation=\"horizontal\" (cdkDragStarted)=\"dragStarted($event)\"\r\n (cdkDropListDropped)=\"dropListDropped($event)\" [trackBy]=\"indexTrackFn\" [dataSource]=\"tvsDataSource\">\r\n <!-- Select Checkbox Column -->\r\n <ng-container matColumnDef=\"row-checkbox\">\r\n <!-- HEADER -->\r\n <mat-header-cell *matHeaderCellDef class=\"row-checkbox\" style=\"z-index: 2;\">\r\n <mat-checkbox style=\"z-index: 10;\" (change)=\"$event ? masterToggle() : null\"\r\n [checked]=\"rowSelectionModel.hasValue() && isAllSelected()\"\r\n [indeterminate]=\"rowSelectionModel.hasValue() && !isAllSelected()\" *ngIf=\"rowSelectionMode === 'multi'\">\r\n </mat-checkbox>\r\n <!-- <mat-icon *ngIf=\"rowSelectionMode === 'single'\">indeterminate_check_box</mat-icon> -->\r\n </mat-header-cell>\r\n <!-- DATA -->\r\n <mat-cell *matCellDef=\"let row\" class=\"row-checkbox\">\r\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"onRowSelectionChange($event, row)\"\r\n [checked]=\"rowSelectionModel?.isSelected(row)\">\r\n </mat-checkbox>\r\n </mat-cell>\r\n <!-- FOOTER -->\r\n <mat-footer-cell *matFooterCellDef></mat-footer-cell>\r\n </ng-container>\r\n\r\n <!-- Table Columns -->\r\n <ng-container *ngFor=\"let column of columns; let i = index; trackBy: trackColumn\" [matColumnDef]=\"column.name\"\r\n [sticky]=\"column.sticky === 'start' ? true : false\" [stickyEnd]=\"column.sticky === 'end' ? true : false\">\r\n <!-- HEADER -->\r\n <mat-header-cell *matHeaderCellDef cdkDrag [cdkDragDisabled]=\"column?.draggable === false\"\r\n cdkDragBoundary=\"mat-header-row\" cdkDropListLockAxis=\"x\" [ngClass]=\"headerClass(column)\"\r\n [cdkDragData]=\"{name: column.name, columIndex: i}\" [ngStyle]=\"column.style\"\r\n [class.active-resize]=\"resizeColumn.columnIndex == i\" cdkDragBoundary=\"mat-header-row\">\r\n <!-- class=\"left-resize-handler\" -->\r\n <div class=\"resize-handler\"\r\n [ngClass]=\"{'left-resize-handler': tableSetting.direction === 'ltr', 'right-resize-handler': tableSetting.direction === 'rtl'}\"\r\n (mousedown)=\"onResizeColumn($event, i, 'left')\"></div>\r\n <header-filter [field]=\"column\" (filterChanged)=\"filter_onChanged(column, $event)\"\r\n [filters]=\"tvsDataSource.getFilter(column.name)\">\r\n <mat-icon class=\"column-icon\" [ngStyle]=\"{ 'color': column?.iconColor }\">{{column?.icon}}</mat-icon>\r\n <mat-icon *ngIf=\"column?.draggable != false\" class=\"drag-indicator\" cdkDragHandle>drag_indicator</mat-icon>\r\n <div mat-sort-header [matTooltip]=\"column.header\" matTooltipClass=\"cell-tooltip\"\r\n [disabled]=\"column.sort === 'none'\" class=\"header-caption\">{{ column.header }}</div>\r\n </header-filter>\r\n <!-- class=\"right-resize-handler\" -->\r\n <div class=\"resize-handler\"\r\n [ngClass]=\"{'right-resize-handler': tableSetting.direction === 'ltr', 'left-resize-handler': tableSetting.direction === 'rtl'}\"\r\n (mousedown)=\"onResizeColumn($event, i, 'right')\"></div>\r\n </mat-header-cell>\r\n <!-- DATA -->\r\n <mat-cell *matCellDef=\"let row;\" #cell (mouseenter)=\"tooltip_onChanged(column, row, cell,true)\"\r\n (mouseleave)=\"tooltip_onChanged(column, row, cell,false)\" [class]=\"row[column.cellClass]\"\r\n (click)=\"onCellClick($event, row, column)\" [ngClass]=\"cellClass(row?.option, column)\"\r\n [ngStyle]=\"cellStyle(row?.option, column)\" (contextmenu)=\"onContextMenu($event, column, row)\">\r\n <label *ngIf=\"!column.dynamicCellComponent\" (click)=\"onLabelClick($event, row, column)\"\r\n [class.rtl-cell]=\"direction === 'rtl'\" [class.ltr-cell]=\"direction === 'ltr'\" [ngStyle]=\"ellipsis(column)\"\r\n class=\"label-cell\">{{row[column.name]}}</label>\r\n <ng-container *ngIf=\"column.dynamicCellComponent\" dynamicCell [component]=\"column.dynamicCellComponent\"\r\n [column]=\"column\" [row]=\"row\" [onRowEvent]=\"onRowEvent\">\r\n </ng-container>\r\n </mat-cell>\r\n <!-- FOOTER -->\r\n <mat-footer-cell *matFooterCellDef [ngStyle]=\"column.style\">\r\n <div *ngFor=\"let footer of column?.footer\" class=\"footer-column\">\r\n <div [style.height.px]=\"footerHeight\" class=\"footer-row\">\r\n <span> {{footer.aggregateText}}</span>\r\n </div>\r\n </div>\r\n </mat-footer-cell>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"progress\">\r\n <mat-header-cell *matHeaderCellDef [attr.colspan]=\"displayedColumns.length\">\r\n <mat-progress-bar mode=\"indeterminate\" [class.show]=\"pending\">\r\n </mat-progress-bar>\r\n </mat-header-cell>\r\n </ng-container>\r\n\r\n <!-- Expanded Content Column - The detail row is made up of Dynamic Cell -->\r\n <ng-container *ngIf=\"expandColumn.length > 0\" matColumnDef=\"expandedDetail\">\r\n <td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"displayedColumns.length\" class=\"expanded-detail-cell\">\r\n <div class=\"expanded-detail\" [@detailExpand]=\"row == expandedElement ? 'expanded' : 'collapsed'\">\r\n <ng-container dynamicCell [component]=\"expandComponent\" [row]=\"row\" [onRowEvent]=\"onRowEvent\">\r\n </ng-container>\r\n </div>\r\n </td>\r\n </ng-container>\r\n\r\n <!-- Table Menu[ Sort, Visible, Export] -->\r\n <ng-container matColumnDef=\"table-menu\" [stickyEnd]=\"true\" *ngIf=\"setting?.visibleTableMenu !== false\">\r\n <mat-header-cell *matHeaderCellDef class=\"table-menu\">\r\n <table-menu [(tableSetting)]=\"tableSetting\" (menuActionChange)=\"tableMenuActionChange($event)\"></table-menu>\r\n </mat-header-cell>\r\n <mat-cell *matCellDef=\"let row\" class=\"table-menu\">\r\n <row-menu *ngIf=\"rowContextMenuItems && rowContextMenuItems.length > 0\" [rowActionMenu]=\"row?.actionMenu\"\r\n [actionMenus]=\"rowContextMenuItems\" [tableSetting]=\"tableSetting\"\r\n (rowActionChange)=\"rowMenuActionChange($event, row)\"></row-menu>\r\n </mat-cell>\r\n </ng-container>\r\n\r\n <!-- Row Table[Header, Data, Footer] -->\r\n <mat-row *matRowDef=\"let row; columns: displayedColumns;\" (dblclick)=\"onRowDblClick($event, row)\"\r\n (click)=\"onRowClick($event, row)\" [style.height.px]=\"rowHeight\" class=\"table-row\" [ngClass]=\"row?.option?.class\"\r\n [ngStyle]=\"rowStyle(row)\" [class.expanded-row]=\"expandedElement === row\"\r\n [class.row-selection]=\"rowSelectionModel ? rowSelectionModel.isSelected(row) : false\"\r\n (contextmenu)=\"onContextMenu($event, null, row)\">\r\n </mat-row>\r\n\r\n <ng-container *ngIf=\"expandColumn.length > 0\">\r\n <tr mat-row *matRowDef=\"let expandRow; columns: expandColumn\" class=\"detail-row\"></tr>\r\n </ng-container>\r\n\r\n <mat-header-row class=\"header\" [@tableAnimation] *matHeaderRowDef=\"displayedColumns; sticky: sticky\"\r\n [style.top.px]=\"inverseOfTranslation\"></mat-header-row>\r\n <ng-container *ngIf=\"displayedFooter.length > 0\">\r\n <mat-footer-row class=\"footer\" [@tableAnimation] *matFooterRowDef=\"displayedFooter;\"></mat-footer-row>\r\n </ng-container>\r\n <mat-header-row class=\"progress\" *matHeaderRowDef=\"progressColumn; sticky: sticky\"\r\n [style.top.px]=\"inverseOfTranslation + headerHeight - 5\"></mat-header-row>\r\n </mat-table>\r\n</cdk-virtual-scroll-viewport>\r\n<pagination\r\n *ngIf=\"pagingMode !== 'none'\"\r\n [dir]=\"'ltr'\"\r\n [pageIndex]=\"pagination?.pageIndex\"\r\n [pageSize]=\"pagination?.pageSize\"\r\n [pageSizeOptions]=\"pagination?.pageSizeOptions\"\r\n [length]=\"pagination?.length\"\r\n (page)=\"pagination_onChange($event)\">\r\n</pagination>\r\n<!-- <ng-content></ng-content> -->\r\n<ng-container *ngIf=\"showNoData && init === true\">\r\n <div class=\"no-records\" *ngIf=\"tvsDataSource.data.length == 0\">\r\n {{ languagePack?.tableLabels?.NoData }}\r\n <br>\r\n <button mat-icon-button type=\"button\" *ngIf=\"showReload === true\" color=\"primary\" (click)=\"reload_onClick()\">\r\n <mat-icon>autorenew</mat-icon>\r\n </button>\r\n </div>\r\n</ng-container>\r\n\r\n<!-- Context Menu -->\r\n<div style=\"visibility: hidden; position: fixed\" [style.left]=\"contextMenuPosition.x\"\r\n [style.top]=\"contextMenuPosition.y\" [matMenuTriggerFor]=\"contextMenu\">\r\n</div>\r\n<mat-menu #contextMenu=\"matMenu\">\r\n <ng-template matMenuContent let-item=\"item\">\r\n <ng-container *ngFor=\"let menu of contextMenuItems\">\r\n <button mat-button type=\"button\" [class.ltr-menu]=\"tableSetting.direction === 'rtl'\" [color]=\"menu.color\"\r\n class=\"button-menu\" [disabled]=\"menu.disabled\" (click)=\"onContextMenuItemClick(menu)\">\r\n <mat-icon>{{menu.icon}}</mat-icon>\r\n <span [class.text-align-right]=\"tableSetting.direction === 'rtl'\" class=\"text-align-left\">{{menu.text}}</span>\r\n </button>\r\n <mat-divider *ngIf=\"menu.divider === true\"></mat-divider>\r\n </ng-container>\r\n </ng-template>\r\n</mat-menu>\r\n", animations: [tableAnimation, expandAnimation], changeDetection: ChangeDetectionStrategy.OnPush, styles: ["@media print{.print-preview{background-color:#fff;position:fixed;width:100%;height:auto;z-index:99999999;margin:0;padding:0;top:0;left:0;overflow:visible;display:block}}.disable-backdrop-click .cdk-overlay-backdrop.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{pointer-events:none}:host{display:flex;flex-direction:column;table-layout:fixed;min-height:200px;position:relative;overflow:auto;transition:.3s cubic-bezier(.46,-.72,.46,1.54);background-color:#f3f3f3;border:2px #009688}::ng-deep .cdk-virtual-scroll-content-wrapper{left:auto!important}::ng-deep .mat-menu-panel{min-height:48px}.label-cell{width:100%}mat-cell:first-of-type,mat-header-cell:first-of-type:not(.row-checkbox),mat-footer-cell:first-of-type{padding-left:0!important}.rtl-cell{padding-right:20px}.ltr-cell{padding-left:20px}.viewport{height:calc(100% - 0px)}.viewport-with-pagination{height:calc(100% - 48px)}.table-paginator{position:sticky;bottom:0;display:flex;flex-wrap:wrap;max-height:48px;align-items:center;overflow:hidden;direction:ltr}mat-footer-row,mat-row{min-height:auto!important}mat-row,tr.mat-header-row,mat-footer-row{display:flex;border-width:0;border-bottom-width:1px;border-bottom-color:#d2d2d2;border-style:solid;align-items:center;box-sizing:border-box}mat-cell,mat-footer-cell,mat-header-cell{align-self:stretch;color:inherit;background-color:inherit}.mat-table .row-selection{background-color:#f7f5f5}.mat-table .mat-row:hover{background-color:#fafafa}.mat-table mat-cell{box-sizing:border-box}.mat-header-row.progress{border:none;max-height:4px;min-height:4px;height:0;margin-top:-4px;background-color:transparent!important;border-top:transparent!important;background:transparent!important}.mat-header-row.progress .mat-header-cell{border:0;padding:0}.mat-header-row.progress mat-progress-bar{transition:height .3s,opacity .25s linear}.mat-header-row.progress mat-progress-bar:not(.show){height:0;opacity:0}.no-records{display:flex;align-items:center;top:50%;left:50%;margin:-42px 0 0 -25px;line-height:42px;position:absolute;z-index:1;pointer-events:none}.no-records button{pointer-events:initial}::ng-deep .dmf{min-width:100%}::ng-deep dynamic-mat-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .mat-table mat-row .mat-cell mat-form-field{max-width:100%}::ng-deep dynamic-mat-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .mat-table mat-row .mat-cell mat-form-field .mat-form-field-wrapper{padding-bottom:0!important}::ng-deep dynamic-mat-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .mat-table mat-row .mat-cell mat-form-field ::ng-deep .mat-form-field-underline{bottom:0!important}mat-header-cell:hover .left-resize-handler{height:100%;transition:height .4s ease-out}mat-header-cell:hover .right-resize-handler{height:100%;transition:height .4s ease-out}.resize-handler{display:inline-block;min-width:1px;height:0;position:sticky;cursor:col-resize;border-width:0;z-index:10}.left-resize-handler{left:0;padding-right:10px;margin-right:-10px;border-left:solid 2px #8b8b8b}.right-resize-handler{right:0px;padding-left:10px;margin-left:-10px;border-right:solid 2px #8b8b8b}.active-resize{background-color:#f5f5f566}.ltr-menu span{float:left}.button-menu{width:100%;line-height:48px}.button-menu::ng-deep .mat-button-wrapper{display:flex}.button-menu::ng-deep .mat-button-wrapper span{display:inline-block;width:100%;text-align:left}.button-menu::ng-deep .mat-button-wrapper mat-icon{line-height:48px;height:48px;margin:0 5px}mat-button-wrapper .button-menu{display:inline-block!important}.text-align-left{text-align:left!important}.text-align-right{text-align:right!important}.mat-menu-panel{min-height:unset!important}.mat-sort-header-arrow{margin:0 6px!important}cdk-virtual-scroll-viewport{min-height:100px;height:inherit;overflow:auto}.header-caption{font-weight:bolder;font-size:14px;width:100%}.header{-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:#fff}.footer{-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:#fff}.row-checkbox{padding-left:0!important;padding-right:0!important;max-width:46px;min-width:46px}.row-checkbox mat-checkbox{padding:10px}.row-checkbox mat-icon{padding:11px!important}.table-menu{max-width:42px;min-width:0;min-width:initial;padding:0!important;background-color:inherit}:host .mat-header-row>.mat-header-cell:hover .column-icon{opacity:0;transform:translateY(5px);transition:all .2s}.drag-indicator{position:absolute;color:#0000004d;display:flex;opacity:0;transform:translateY(-5px);cursor:pointer;transition-duration:.4s;transition-property:opacity,transform;cursor:move}:host .mat-header-row>.mat-header-cell:hover .drag-indicator{opacity:1;pointer-events:fill;transform:translateY(0)}.drag-indicator:hover{color:#bfc0c0!important}.cdk-drag-preview{color:#000;min-height:55px;border:solid 1px #d4d4d4;background-color:#f5f5f5;box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{border:dotted 1px #9c9c9c;background-color:#d3d3d3;content:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging{transition:transform .25s cubic-bezier(0,0,.2,1)}.detail-row{height:0px;display:inline!important;width:100%}.table-row:not(.expanded-row):hover{background:whitesmoke}.table-row:not(.expanded-row):active{background:#efefef}.table-row mat-cell{border-bottom-width:0}.expanded-detail{overflow:hidden;display:flex;background-color:#fafafa}.expanded-detail-cell{display:block;border-width:0;padding:0!important;width:100%;z-index:2}::ng-deep .cell-tooltip{padding:8px;font-size:12px;min-width:100px;text-align:center;margin-right:-20px}.tooltip{position:relative;display:inline-block;border-bottom:1px dotted black}.tooltip .tooltiptext{visibility:hidden;min-width:120px;background-color:#e91e63;color:#fff;text-align:center;border-radius:6px;padding:5px 0;position:absolute;z-index:1;left:0;top:43px;margin-left:-86%}.tooltip:hover .tooltiptext{visibility:visible;white-space:pre}::ng-deep .mat-footer-cell{flex-direction:column!important}.footer-column{display:flex;flex-direction:column}.footer-column .footer-row{display:flex;flex-direction:row}.footer-column .footer-row span{display:inherit;align-items:center}\n"] },] } ]; /** * @type {function(): !Array<(null|{ * type: ?, * decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>), * })>} * @nocollapse */ DynamicMatTableComponent.ctorParameters = () => [ { type: MatDialog }, { type: Renderer2 }, { type: TableIntl }, { type: TableService }, { type: ChangeDetectorRef }, { type: Overlay }, { type: OverlayContainer }, { type: OverlayPositionBuilder }, { type: TableSetting } ]; /** @type {!Object<string, !Array<{type: !Function, args: (undefined|!Array<?>)}>>} */ DynamicMatTableComponent.propDecorators = { tbl: [{ type: ViewChild, args: ["tbl", { static: true },] }], setting: [{ type: Input }], height: [{ type: HostBinding, args: ["style.height.px",] }], tooltipRef: [{ type: ViewChild, args: ["tooltip",] }], contextMenu: [{ type: ViewChild, args: [MatMenuTrigger,] }], printRef: [{ type: ViewChild, args: ["printRef", { static: true },] }], printContentRef: [{ type: ViewChild, args: ["printContentRef", { static: true },] }], headerFilterList: [{ type: ContentChildren, args: [HeaderFilterComponent,] }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1tYXQtdGFibGUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZHluYW1pYy1tYXQtdGFibGUvc3JjL2xpYi9keW5hbWljLW1hdC10YWJsZS9keW5hbWljLW1hdC10YWJsZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFHVCxTQUFTLEVBQ1QsVUFBVSxFQUNWLFNBQVMsRUFDVCxXQUFXLEVBQ1gsU0FBUyxFQUNULGlCQUFpQixFQUNqQixLQUFLLEVBRUwsZUFBZSxFQUNmLFFBQVEsRUFFUixXQUFXLEVBQ1gsdUJBQXVCLEdBQ3hCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUczRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUNwRixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckQsT0FBTyxFQUNMLE9BQU8sRUFDUCxVQUFVLEVBQ1YsS0FBSyxFQUNMLE9BQU8sRUFDUCxLQUFLLEVBQ0wsT0FBTyxFQUNQLEtBQUssR0FDTixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFeEQsT0FBTyxFQUdMLGVBQWUsR0FDaEIsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxPQUFPLEVBQVcsaUJBQWlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0QsT0FBTyxFQUFlLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JB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