UNPKG

ngx-ui-hero

Version:

Simple, fast and reliable utilities for Angular.

856 lines 178 kB
import { clone, filter, find, map, orderBy, some, sum, sumBy } from "lodash-es"; import { BsModalService } from "ngx-bootstrap/modal"; import { PaginationComponent, } from "ngx-bootstrap/pagination"; import { Component, ContentChild, EventEmitter, Inject, Input, IterableDiffers, Optional, Output, Renderer2, TemplateRef, ViewChild, } from "@angular/core"; import { DomSanitizer } from "@angular/platform-browser"; import { EnumAutoFitMode, EnumDataGridMode, } from "./config/data-grid-config"; import { DATAGRID_CONFIG } from "./config/data-grid-config.constants"; import { DatagridExportingModalComponent } from "./datagrid-exporting-modal/datagrid-exporting-modal.component"; import { ActionsColumnDirective } from "./directives/data-grid-templates.directive"; import { DataGridSortingModel, EnumAlignment, EnumSortDirection, } from "./models/data-grid-column.model"; import * as i0 from "@angular/core"; import * as i1 from "ngx-bootstrap/modal"; import * as i2 from "@angular/platform-browser"; import * as i3 from "@angular/common"; import * as i4 from "@angular/forms"; import * as i5 from "../ui/components/spinner/spinner.component"; import * as i6 from "ngx-bootstrap/pagination"; import * as i7 from "ngx-bootstrap/dropdown"; import * as i8 from "ngx-bootstrap/popover"; import * as i9 from "./components/column-filter/column-filter.component"; let identifier = 0; export class GridDataModel { } export class GridRowModel { } export class GridColumnModel { } export class DataGridComponent { constructor(defaultOptions, iterableDiffers, modalService, renderer, sanitizer) { this.iterableDiffers = iterableDiffers; this.modalService = modalService; this.renderer = renderer; this.sanitizer = sanitizer; this.initialRenderApplied = false; this.sortApplied = false; this.animating = false; this.selectAll = false; this.isResizing = false; this.isReordering = false; this.currentElementBeingReorderedFromIndex = -1; this.currentElementBeingReorderedToIndex = -1; this.currentPage = 1; this.identifier = `datagrid-${identifier++}`; this.debugMode = false; this.tableId = this.identifier; this.emptyResultsMessage = "No results found at this moment."; this.infoMessage = "Showing records from {recordsFrom} to {recordsTo} of {totalRecords} records found."; this.animated = true; this.striped = true; this.bordered = true; this.hoverEffect = true; this.responsive = true; this.showCheckboxColumn = false; this.showSelectAllCheckbox = true; this.selectAllPages = true; this.checkBoxMode = 0; this.showSummaries = false; this.allowExports = false; this.exportButtonLabel = "Export"; this.exportedFileName = "Export"; this.exportedExcelSheetName = "Sheet"; this.initialColumnToSort = 0; this.initialSortDirection = EnumSortDirection.Ascending; this.mode = EnumDataGridMode.OnClient; this.itemsPerPage = 10; this.maxSize = 10; this.boundaryLinks = true; this.directionLinks = true; this.rotate = true; this.showActionsColumn = false; this.showInfos = true; this.actionsColumnCaption = "#"; this.actionsColumnWidth = "100px"; this.firstText = "First"; this.previousText = "Previous"; this.nextText = "Next"; this.lastText = "Last"; this.autoFitMode = EnumAutoFitMode.ByContent; this.allowColumnResize = true; this.allowColumnFilters = true; this.allowColumnReorder = true; this.fixedHeader = false; this.minHeight = 200; this.filterPlaceholder = "Filter..."; this.filterPlacement = "bottom"; this.OnSelectionChanged = new EventEmitter(); this.OnRowSelected = new EventEmitter(); this.OnRowRendered = new EventEmitter(); this.OnPaginate = new EventEmitter(); this.OnSort = new EventEmitter(); this.OnColumnFiltered = new EventEmitter(); this._maxWidth = 400; this._minColumnWidth = 150; Object.assign(this, defaultOptions); if (defaultOptions.paging) { Object.assign(this, defaultOptions.paging); } if (defaultOptions.styles) { Object.assign(this, defaultOptions.styles); } if (defaultOptions.exporting) { Object.assign(this, defaultOptions.exporting); } if (defaultOptions.filtering) { Object.assign(this, defaultOptions.filtering); } if (defaultOptions.reordering) { Object.assign(this, defaultOptions.reordering); } this._dataDiffer = this.iterableDiffers.find([]).create(null); } get data() { return this._externalData; } set data(value) { this._externalData = value; if (this.isUndefinedOrNull(value) && !this.isUndefinedOrNull(this._internalData)) { this.initializeRendering(true); } } ngOnInit() { this.draw(); } ngDoCheck() { let dataHasChanges = this._dataDiffer.diff(this._externalData); if (dataHasChanges && this.initialRenderApplied) { this.initializeRendering(true); } } ToogleSorting(column) { if (!column.sortable || !column.sort || this.isResizing) { return; } if (this.mode == EnumDataGridMode.OnClient) { if (column.sort.sorting) { if (column.sort.sortDirection == EnumSortDirection.Ascending) { column.sort.sortDirection = EnumSortDirection.Descending; } else { column.sort.sortDirection = EnumSortDirection.Ascending; } } else { for (let i = 0; i < this.columns.length; i++) { this.columns[i].sort.sorting = false; } column.sort.sorting = true; column.sort.sortDirection = EnumSortDirection.Ascending; } this.sortOnClient(column); this.paginateOnClient(this.currentPage); } else { if (this.isUndefinedOrNull(this.OnSort)) { console.error("The [OnSort] callback must be provided when DataGrid Server mode is enabled."); return; } this.OnSort.emit(column); } } PageChanged(event) { if (this.mode == EnumDataGridMode.OnClient) { this.paginateOnClient(event.page); } else { if (this.isUndefinedOrNull(this.OnPaginate)) { console.error("The [OnPaginate] callback must be provided when DataGrid Server mode is enabled."); return; } } this.OnPaginate.emit(event); } GetInfo() { let result = this.infoMessage; let recordsFrom = this.currentPage * this.itemsPerPage - (this.itemsPerPage - 1); let recordsTo = this.currentPage * this.itemsPerPage; let totalRecords = this.totalItems; if (recordsTo > totalRecords) { recordsTo = recordsTo - (recordsTo - totalRecords); } return result .replace("{recordsFrom}", recordsFrom.toString()) .replace("{recordsTo}", recordsTo.toString()) .replace("{totalRecords}", totalRecords.toString()); } Redraw() { this.draw(); } RenderPropertyValue(propertyPath, object) { if (!propertyPath) return null; let parts = propertyPath.split("."); let property = object || {}; for (let i = 0; i < parts.length; i++) { if (!property) { return null; } property = property[parts[i]]; } return property; } RenderColumnSummary(column) { if (!this.gridData || !this.gridData.hasData) { return 0; } return sumBy(this.gridData.rows, (x) => Number(this.RenderPropertyValue(column.data, x.model))); } HasSummarizableColumns() { if (!this.columns || this.columns.length == 0) { return false; } return some(this.columns, (x) => x.summarizable); } OnSelectAllChanged() { if (!this.gridData || !this.gridData.hasData) { return; } for (let i = 0; i < this.gridData.rows.length; i++) { this.gridData.rows[i].selected = this.selectAll; if (!this.selectAllPages) { switch (this.mode) { case EnumDataGridMode.OnServer: this._internalData[i].selected = this.selectAll; break; default: this._internalData[i + this.itemsPerPage * (this.currentPage - 1)].selected = this.selectAll; break; } } } if (this.selectAllPages) { for (let i = 0; i < this._internalData.length; i++) { this._internalData[i].selected = this.selectAll; } } this.OnSelectionChanged.emit(); } OnRowSelectedChanged(row, rowIndex) { switch (this.mode) { case EnumDataGridMode.OnServer: this._internalData[rowIndex].selected = row.selected; break; default: this._internalData[rowIndex + this.itemsPerPage * (this.currentPage - 1)].selected = row.selected; break; } this.handleSelectAllCheckboxState(); this.OnRowSelected.emit(row); this.OnSelectionChanged.emit(); } async ExportToExcel(event) { event.preventDefault(); let _data = this.boundedExportCallback ? await this.boundedExportCallback() : this._externalData; this.modalService.show(DatagridExportingModalComponent, { class: "modal-md", initialState: { data: _data, columns: this.columns.slice(0), exportedFileName: this.exportedFileName, exportedExcelSheetName: this.exportedExcelSheetName, initialColumnToSort: this.initialColumnToSort, initialSortDirection: this.initialSortDirection, }, }); return false; } OnResizerMouseDown(e) { if (!this.allowColumnResize) return; this.isResizing = true; var pageX, curCol, nxtCol, curColWidth, nxtColWidth; curCol = e.target.parentElement; nxtCol = curCol.nextElementSibling; pageX = e.pageX; var padding = this.paddingDiff(curCol); curColWidth = curCol.offsetWidth - padding; if (nxtCol) nxtColWidth = nxtCol.offsetWidth - padding; var onMouseMoveCallback = (e) => { if (curCol) { var diffX = e.pageX - pageX; if (nxtCol) nxtCol.style.width = nxtColWidth - diffX + "px"; curCol.style.width = curColWidth + diffX + "px"; } }; var onMouseUpCallback = (e) => { curCol = undefined; nxtCol = undefined; pageX = undefined; nxtColWidth = undefined; curColWidth = undefined; setTimeout(() => { this.isResizing = false; }); document.removeEventListener("mousemove", onMouseMoveCallback); document.removeEventListener("mouseup", onMouseUpCallback); }; document.addEventListener("mousemove", onMouseMoveCallback); document.addEventListener("mouseup", onMouseUpCallback); } OnColumnMouseDown(e, index) { if (!this.allowColumnReorder) return; var onDragStartCallback = (e) => { var img = document.createElement("img"); e.dataTransfer.setDragImage(img, 0, 0); this.isReordering = true; this.currentElementBeingReorderedFromIndex = index; this.renderer.addClass(e.target.parentElement.parentElement, "dragging"); e.target.addEventListener("dragenter", (e) => onDragEnterCallback(e, index)); e.target.addEventListener("dragend", onDragEndCallback); $(`#${this.identifier} thead tr th.column`).each((i, el) => { if (i != index) { el.addEventListener("dragenter", (e) => onDragEnterCallback(e, i)); el.addEventListener("dragover", onDragOverCallback); } }); }; var onDragEndCallback = (e) => { if (this.currentElementBeingReorderedFromIndex != this.currentElementBeingReorderedToIndex) { this.debug("From", this.currentElementBeingReorderedFromIndex, "To", this.currentElementBeingReorderedToIndex); var columnFromCopy = Object.assign({}, this.columns[this.currentElementBeingReorderedFromIndex]); var columnsCopy = Object.assign([], this.columns); columnsCopy.splice(this.currentElementBeingReorderedFromIndex, 1); columnsCopy.splice(this.currentElementBeingReorderedToIndex, 0, columnFromCopy); this.columns = columnsCopy; this.updateColumnReorderingDefinition(); } this.isReordering = false; this.currentElementBeingReorderedFromIndex = -1; this.currentElementBeingReorderedToIndex = -1; this.renderer.removeClass(e.target.parentElement.parentElement, "dragging"); e.target.removeEventListener("dragenter", (e) => onDragEnterCallback(e, index)); e.target.removeEventListener("dragend", onDragEndCallback); $(`#${this.identifier} thead tr th.column`).each((i, el) => { if (i != index) { el.removeEventListener("dragenter", (e) => onDragEnterCallback(e, i)); el.removeEventListener("dragover", onDragOverCallback); } }); this.initializeRendering(); }; var onDragEnterCallback = (e, i) => { this.currentElementBeingReorderedToIndex = i; }; var onDragOverCallback = (e) => { e.preventDefault(); }; var onMouseUpCallback = (e) => { e.target.removeEventListener("dragstart", onDragStartCallback); e.target.removeEventListener("mouseup", onMouseUpCallback); }; e.target.addEventListener("dragstart", onDragStartCallback); e.target.addEventListener("mouseup", onMouseUpCallback); } OnColumnFilterClick(e, column) { if (!column.isFiltersOpenned) { this.closeAllColumnsFilters(); column.isFiltersOpenned = true; } else { this.closeAllColumnsFilters(); } e.stopPropagation(); } OnFiltersChange(column) { if (this.mode == EnumDataGridMode.OnServer) { this.OnColumnFiltered.emit(column); } else { this.initializeRendering(); } } HandleColumnClick(row, currentData, rowIndex, column) { if (!column.onClick) return; column.onClick(row, currentData, rowIndex, column); } HandleColumnRendering(row, currentData, rowIndex, column) { if (!column.render) return ""; return this.sanitizer.bypassSecurityTrustHtml(column.render(row, currentData, rowIndex)); } draw(redrawing) { this.initializeColumns(); this.initializeRendering(redrawing); } initializeRendering(redrawing) { setTimeout(() => { this.initializeGridData(); this.initializeFilters(); this.initializePaging(redrawing); this.initializeSorting(); this.handleAutoFit(); this.handleInitialRenderingFlag(); }, 0); } initializeGridData() { if (this._externalData) { this._internalData = Object.assign([], this._externalData); } else { this._internalData = []; } if (this.mode == EnumDataGridMode.OnServer) { this.initGridDataModel(Object.assign([], this._internalData)); this.handleRowRenders(); } } initGridDataModel(data) { this.gridData = { hasData: data && data.length > 0, rows: map(data, (row, rowIndex) => { let _row = { selected: row.selected, model: row, columns: map(this.columns, (column, columnIndex) => { let _column = { isHtml: column.render != undefined, }; if (column.data) { if (column.data.split(".").length > 1) { _column.value = this.RenderPropertyValue(column.data, row); } else { _column.value = row[column.data]; } } if (_column.isHtml) { _column.value = this.HandleColumnRendering(row, _column.value, rowIndex, column); } return _column; }), }; return _row; }), }; } initializeColumns() { if (!this.columns || this.columns.length == 0) { console.error("Param [columns] cannot be undefined or empty."); return; } if (!this._externalColumns) this._externalColumns = clone(this.columns); for (let i = 0; i < this.columns.length; i++) { let target = { caption: null, captionAlignment: EnumAlignment.Left, captionClasses: null, data: null, dataAlignment: EnumAlignment.Left, dataClasses: null, sortable: true, filterable: true, visible: true, index: i, }; Object.assign(target, this.columns[i]); this.columns[i] = target; this.columns[i].sort = new DataGridSortingModel(); if (!this.isUndefinedOrNull(this.initialColumnToSort) && this.initialColumnToSort == i) { this.columns[i].sort.sorting = true; if (this.columns[i].sortDirection) { this.columns[i].sort.sortDirection = this.columns[i].sortDirection; } else { this.columns[i].sort.sortDirection = this.initialSortDirection; } } } if (!this._internalColumns) this._internalColumns = clone(this.columns); this.filterColumnsThatShouldBeVisible(); this.verifyColumnIndexPersistences(); } initializeSorting() { if (this.isUndefinedOrNull(this._internalData) || this.mode == EnumDataGridMode.OnServer || this.isUndefinedOrNull(this.initialColumnToSort)) { this.sortApplied = true; return; } if (this.initialColumnToSort > this.columns.length - 1) { console.error("Param [initialColumnToSort] greater than the number of columns."); this.sortApplied = true; return; } const columnToSort = find(this.columns, (x) => x.sortable && x.sort && x.sort.sorting); if (this.isUndefinedOrNull(columnToSort)) { this.paginateOnClient(this.currentPage); } else { this.sortOnClient(columnToSort); this.paginateOnClient(this.currentPage); } this.sortApplied = true; } initializePaging(redrawing) { if (!this.currentPage) { this.currentPage = 1; } if (this._internalData && this.mode == EnumDataGridMode.OnClient) { this.totalItems = this._internalData.length; } let currentPageFitsTheNumberOfItems = this.totalItems > this.itemsPerPage * (this.currentPage - 1); let shouldResetCurrentPage = this.currentPage > 1 && this.mode == EnumDataGridMode.OnClient && !currentPageFitsTheNumberOfItems; if ((redrawing && this.mode == EnumDataGridMode.OnClient) || shouldResetCurrentPage) { this.currentPage = 1; } if (this.paginator) { this.paginator.page = this.currentPage; this.paginator.totalItems = this.totalItems; } } paddingDiff(col) { if (this.getStyleVal(col, "box-sizing") == "border-box") { return 0; } var padLeft = this.getStyleVal(col, "padding-left"); var padRight = this.getStyleVal(col, "padding-right"); return parseInt(padLeft) + parseInt(padRight); } getStyleVal(elm, css) { return window.getComputedStyle(elm, null).getPropertyValue(css); } isUndefinedOrNull(value) { return value == undefined || value == null; } sortOnClient(column) { this._internalData = orderBy(this._internalData, [column.data], [column.sort.sortDirection]); } paginateOnClient(page) { const startItem = (page - 1) * this.itemsPerPage; const endItem = page * this.itemsPerPage; this.initGridDataModel(this._internalData.slice(startItem, endItem)); this.handleRowRenders(); this.handleSelectAllCheckboxState(); this.handleAutoFit(); } handleAutoFit() { switch (this.autoFitMode) { case EnumAutoFitMode.ByContent: this.autofitByContent(); break; case EnumAutoFitMode.ByCaption: this.autofitByCaption(); break; default: this.autofitByFixedWidths(); break; } } autofitByContent() { if (!this.gridData || !this.gridData.hasData) { this.autofitByCaption(); return; } this.animating = true; setTimeout(() => { let widths = []; let gridWidth = $(`#${this.tableId}`).parent().width(); if (gridWidth == 0 && $(`#${this.tableId}`).parents(".tab-content").length) { gridWidth = $(`#${this.tableId}`).parents(".tab-content").width(); } for (let rowIndex = 0; rowIndex < this.gridData.rows.length; rowIndex++) { for (let columnIndex = 0; columnIndex < this.columns.length; columnIndex++) { let width = this._minColumnWidth; let currentData = null; if (!this.gridData.rows[rowIndex].columns[columnIndex].isHtml) { currentData = this.gridData.rows[rowIndex].columns[columnIndex].value; } if (!this.isUndefinedOrNull(currentData)) { width = currentData.toString().length * 10 + 20; } if (!this.isUndefinedOrNull(this.columns[columnIndex].caption)) { let widthByCaption = this.columns[columnIndex].caption.toString().length * 10 + 40; if (widthByCaption > width) { width = widthByCaption; if (this.allowColumnResize) { width += 20; } if ((this.allowColumnFilters && this.columns[columnIndex].filterable && this.isUndefinedOrNull(widths[columnIndex])) || width > widths[columnIndex]) { width += 30; } } } if (this.isUndefinedOrNull(widths[columnIndex]) || width > widths[columnIndex]) { if (width > this._maxWidth) { widths[columnIndex] = this._maxWidth; } else { widths[columnIndex] = width; } } } } this.setDataGridWidths(widths, gridWidth); this.animating = false; }, 0); } autofitByCaption() { this.animating = true; setTimeout(() => { for (let columnIndex = 0; columnIndex < this.columns.length; columnIndex++) { if (this.isUndefinedOrNull(this.columns[columnIndex].width)) { let widthByCaption = this.columns[columnIndex].caption.toString().length * 10 + 40; if (this.allowColumnResize) { widthByCaption += 10; } if (this.allowColumnFilters && this.columns[columnIndex].filterable) { widthByCaption += 30; } this.columns[columnIndex].width = `${widthByCaption}px`; } } this.animating = false; }, 0); } autofitByFixedWidths() { this.animating = true; setTimeout(() => { for (let columnIndex = 0; columnIndex < this.columns.length; columnIndex++) { if (this.isUndefinedOrNull(this.columns[columnIndex].width)) { this.columns[columnIndex].width = "150px"; } } this.animating = false; }, 0); } handleSelectAllCheckboxState() { if (!this.gridData || !this.gridData.hasData) { this.selectAll = false; return; } this.selectAll = this.gridData.rows.filter((x) => x.selected).length == this.gridData.rows.length; } setDataGridWidths(widths, gridWidth) { let initialColumnsWidths = new Array(this.columns.length); let _externalColumns = this._externalColumns.filter((x) => x.visible == undefined || x.visible == true); for (let i = 0; i < _externalColumns.length; i++) { let columnDefaultWidth = _externalColumns[i].width; let def = this.getColumnReorderingDefinitionFrom(_externalColumns[i]); if (!def) { initialColumnsWidths[i] = columnDefaultWidth; continue; } initialColumnsWidths[def.userIndex] = columnDefaultWidth; } this.debug("initialColumnsWidths", initialColumnsWidths); let totalColumnsWidth = sum(widths); let totalColumnsWidthGreaterThanGrid = totalColumnsWidth > gridWidth; if (!totalColumnsWidthGreaterThanGrid) { let biggestColumnIndex = 0; let biggestWidth = widths[widths.length - 1]; for (let i = widths.length - 2; i >= 0; i--) { if (widths[i] > biggestWidth) { biggestWidth = widths[i]; biggestColumnIndex = i; } } for (let columnIndex = 0; columnIndex < this.columns.length; columnIndex++) { if (columnIndex == biggestColumnIndex) { this.columns[columnIndex].width = `auto`; if (widths[columnIndex] >= this._maxWidth) { if (!this.columns[columnIndex].dataClasses) { this.columns[columnIndex].dataClasses = ""; } this.columns[columnIndex].dataClasses += " td-break-word"; } } else { this.columns[columnIndex].width = `${widths[columnIndex]}px`; } } } else { for (let columnIndex = 0; columnIndex < this.columns.length; columnIndex++) { if (widths[columnIndex] >= this._maxWidth) { if (!this.columns[columnIndex].dataClasses) { this.columns[columnIndex].dataClasses = ""; } this.columns[columnIndex].dataClasses += " td-break-word"; } this.columns[columnIndex].width = `${widths[columnIndex]}px`; } } for (let i = 0; i < initialColumnsWidths.length; i++) { if (initialColumnsWidths[i]) { this.columns[i].width = initialColumnsWidths[i]; } } } handleInitialRenderingFlag() { if (!this.initialRenderApplied) { this.initialRenderApplied = true; } } initializeFilters() { if (!this.columns || this.columns.length == 0 || !this.data || this.data.length == 0 || this.mode == EnumDataGridMode.OnServer) return; let filters = []; for (let i = 0; i < this.columns.length; i++) { if (this.columns[i].simpleFilter) { filters.push(this.columns[i].simpleFilter); } if (this.columns[i].customFilters && this.columns[i].customFilters.length > 0) { filters.push(...this.columns[i].customFilters); } } if (!filters || filters.length == 0) return; this._internalData = this.data.filter((row, rowIndex) => { for (let i = 0; i < filters.length; i++) { let value = null; if (filters[i].column.render) value = filters[i].column.render(row, this.RenderPropertyValue(filters[i].column.data, row), rowIndex); else value = this.RenderPropertyValue(filters[i].column.data, row); if (!filters[i].operator.validate(filters[i].filter, value)) { return false; } } return true; }); } closeAllColumnsFilters() { if (!this.columns || this.columns.length == 0) return; for (let i = 0; i < this.columns.length; i++) { this.columns[i].isFiltersOpenned = false; } } handleRowRenders() { if (!this.gridData || !this.gridData.hasData) return; for (let i = 0; i < this.gridData.rows.length; i++) { this.OnRowRendered.emit(this.gridData.rows[i]); } } verifyColumnIndexPersistences() { if (!this.userPreferencesKey) return; let definition = this.getOrCreateColumnReorderingDefinition(); this.applyColumnReorderingDefinition(definition); } getColumnReorderingDefinition() { if (this._columnDefinitions) return this._columnDefinitions; this.debug("Readed from localstorage"); let json = localStorage.getItem(this.userPreferencesKey); this._columnDefinitions = json ? JSON.parse(json) : null; return this._columnDefinitions; } getOrCreateColumnReorderingDefinition() { let definition = this.getColumnReorderingDefinition(); if (!definition || this.definitionIsNotCompatibleAnymore(definition)) { return this.buildColumnReorderingDefinition(); } return definition; } buildColumnReorderingDefinition() { let definition = { key: this.userPreferencesKey, data: this.columns.map((c) => { let item = { caption: c.caption, originalIndex: c.index, userIndex: c.index, }; return item; }), }; this._columnDefinitions = definition; localStorage.setItem(this.userPreferencesKey, JSON.stringify(definition)); this.debug("Rebuilded ColumnReorderingDefinition"); return definition; } definitionIsNotCompatibleAnymore(definition) { this.debug("Compatibility checking on:", definition); let hasDifferentNumberOfColumns = this.columns.length != definition.data.length; this.debug("hasDifferentNumberOfColumns", hasDifferentNumberOfColumns); if (hasDifferentNumberOfColumns) return true; let hasDifferencesByCaption = filter(definition.data, (def) => this.columns[def.originalIndex].caption != def.caption).length > 0; this.debug("hasDifferencesByCaption", hasDifferencesByCaption); return hasDifferencesByCaption; } applyColumnReorderingDefinition(definition) { for (let i = 0; i < this.columns.length; i++) { let def = find(definition.data, (x) => x.caption == this.columns[i].caption); if (!def) continue; this.columns[i].index = def.userIndex; this.debug(this.columns[i].caption, this.columns[i].index); } this.columns = orderBy(this.columns, (x) => x.index); } updateColumnReorderingDefinition() { if (!this.userPreferencesKey) return; let definition = this.getColumnReorderingDefinition(); for (let i = 0; i < this.columns.length; i++) { this.columns[i].index = i; let def = definition.data.find((x) => x.caption == this.columns[i].caption); if (!def) continue; def.userIndex = i; } this._columnDefinitions = definition; localStorage.setItem(this.userPreferencesKey, JSON.stringify(definition)); } getColumnReorderingDefinitionFrom(column) { if (!this.userPreferencesKey) return undefined; let definition = this.getColumnReorderingDefinition(); if (!definition) return undefined; let def = definition.data.find((x) => x.caption == column.caption); if (!def) return undefined; return def; } filterColumnsThatShouldBeVisible() { this.columns = this._internalColumns.filter((x) => x.visible); } debug(message, ...params) { if (!this.debugMode) return; console.log(message, ...params); } } DataGridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DataGridComponent, deps: [{ token: DATAGRID_CONFIG, optional: true }, { token: i0.IterableDiffers }, { token: i1.BsModalService }, { token: i0.Renderer2 }, { token: i2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); DataGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DataGridComponent, selector: "datagrid", inputs: { debugMode: "debugMode", tableId: "tableId", columns: "columns", emptyResultsMessage: "emptyResultsMessage", infoMessage: "infoMessage", animated: "animated", striped: "striped", bordered: "bordered", hoverEffect: "hoverEffect", responsive: "responsive", showCheckboxColumn: "showCheckboxColumn", showSelectAllCheckbox: "showSelectAllCheckbox", selectAllPages: "selectAllPages", checkBoxMode: "checkBoxMode", showSummaries: "showSummaries", allowExports: "allowExports", exportButtonLabel: "exportButtonLabel", exportedFileName: "exportedFileName", exportedExcelSheetName: "exportedExcelSheetName", initialColumnToSort: "initialColumnToSort", initialSortDirection: "initialSortDirection", mode: "mode", totalItems: "totalItems", itemsPerPage: "itemsPerPage", maxSize: "maxSize", boundaryLinks: "boundaryLinks", directionLinks: "directionLinks", rotate: "rotate", showActionsColumn: "showActionsColumn", showInfos: "showInfos", actionsColumnCaption: "actionsColumnCaption", actionsColumnWidth: "actionsColumnWidth", firstText: "firstText", previousText: "previousText", nextText: "nextText", lastText: "lastText", autoFitMode: "autoFitMode", allowColumnResize: "allowColumnResize", allowColumnFilters: "allowColumnFilters", allowColumnReorder: "allowColumnReorder", fixedHeader: "fixedHeader", minHeight: "minHeight", maxHeight: "maxHeight", userPreferencesKey: "userPreferencesKey", filterPlaceholder: "filterPlaceholder", filterPlacement: "filterPlacement", boundedExportCallback: "boundedExportCallback", data: "data" }, outputs: { OnSelectionChanged: "OnSelectionChanged", OnRowSelected: "OnRowSelected", OnRowRendered: "OnRowRendered", OnPaginate: "OnPaginate", OnSort: "OnSort", OnColumnFiltered: "OnColumnFiltered" }, queries: [{ propertyName: "actionsColumnTemplate", first: true, predicate: ActionsColumnDirective, descendants: true, read: TemplateRef, static: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: ["paginator"], descendants: true }], ngImport: i0, template: "<div class=\"ui-hero-datagrid\">\n <div \n [ngClass]=\"{\n 'table-responsive': responsive,\n 'fixed-header': fixedHeader\n }\"\n [ngStyle]=\"{\n 'max-height.px': fixedHeader && maxHeight > 0 ? maxHeight : 'auto',\n 'min-height.px': fixedHeader && minHeight > 0 ? minHeight : 'auto'\n }\">\n <table [id]=\"tableId\" class=\"table\" [ngClass]=\"{\n 'table-striped': striped,\n 'table-bordered': bordered,\n 'table-hover': hoverEffect,\n 'table-animated': animated && initialRenderApplied && !isResizing,\n 'table-animating': animating && initialRenderApplied,\n 'table-fixed': autoFitMode == 1 || autoFitMode == 2,\n 'table-not-resizing': !isResizing,\n 'd-none': !initialRenderApplied\n }\">\n <thead>\n <tr>\n <th class=\"\" *ngIf=\"showCheckboxColumn && gridData?.hasData\" style=\"width: 50px;\">\n\n <div class=\" custom-control custom-switch\" *ngIf=\"checkBoxMode == 1 && showSelectAllCheckbox\">\n <input type=\"checkbox\" class=\"custom-control-input\" [id]=\"'customSwitchDataGrid' + tableId \" [(ngModel)]=\"selectAll\" (change)=\"OnSelectAllChanged()\" > \n <label class=\"custom-control-label\" [for]=\"'customSwitchDataGrid' + tableId\"></label> \n </div>\n\n <input type=\"checkbox\" [(ngModel)]=\"selectAll\" (change)=\"OnSelectAllChanged()\" *ngIf=\"checkBoxMode == 0 && showSelectAllCheckbox\" />\n </th>\n <th class=\"action text-center\" *ngIf=\"showActionsColumn\" [ngStyle]=\"{'width': actionsColumnWidth}\">{{actionsColumnCaption}}</th>\n <th *ngFor=\"let column of columns; let i = index;\" \n (click)=\"ToogleSorting(column)\" \n class=\"column {{column.captionClasses}}\" \n [draggable]=\"false\"\n [ngStyle]=\"{'width': column.width}\" \n [ngClass]=\"{\n 'sortable': column.sortable,\n 'sorting': column.sort?.sorting,\n 'asc': column.sort?.sortDirection == 'asc',\n 'desc': column.sort?.sortDirection == 'desc'\n }\">\n <div class=\"d-flex justify-content-between align-items-center\"> \n <div class=\"flex-grow-1\" \n [ngClass]=\"{'text-center': column.captionAlignment == 1, 'text-right': column.captionAlignment == 2}\" \n [draggable]=\"allowColumnReorder && !isResizing\" \n (mousedown)=\"OnColumnMouseDown($event, i)\"\n [innerHtml]=\"column.renderCaption ? column.renderCaption() : column.caption\"> \n </div>\n <i class=\"fa fa-sort ml-1\" *ngIf=\"column.sortable && !column.sort?.sorting && gridData?.hasData\"></i>\n <i class=\"fa fa-sort-amount-asc ml-1\" *ngIf=\"column.sortable && column.sort?.sorting && column.sort?.sortDirection == 'asc' && gridData?.hasData\"></i>\n <i class=\"fa fa-sort-amount-desc ml-1\" *ngIf=\"column.sortable && column.sort?.sorting && column.sort?.sortDirection == 'desc' && gridData?.hasData\"></i>\n\n <button type=\"button\" class=\"btn btn-sm btn-filter ml-2 mr-1\" *ngIf=\"allowColumnFilters && column.filterable && data?.length > 0\"\n [popover]=\"popFilters\" triggers=\"\" [isOpen]=\"column.isFiltersOpenned\" [placement]=\"filterPlacement\" [adaptivePosition]=\"false\" container=\"body\" (click)=\"OnColumnFilterClick($event, column)\" [ngClass]=\"{\n 'btn-primary': column.simpleFilter || column.customFilters?.length > 0\n }\">\n <i class=\"fa fa-filter\"></i>\n </button>\n\n <ng-template #popFilters>\n <ui-column-filter \n [column]=\"column\" \n [data]=\"data\" \n [filterPlaceholder]=\"filterPlaceholder\" \n [emptyResultsMessage]=\"emptyResultsMessage\" \n (onChange)=\"OnFiltersChange($event)\">\n </ui-column-filter>\n </ng-template>\n </div>\n <div class=\"resizer\" *ngIf=\"allowColumnResize\" (mousedown)=\"OnResizerMouseDown($event)\"></div>\n </th>\n </tr>\n </thead>\n <tbody *ngIf=\"sortApplied\">\n <tr *ngFor=\"let row of gridData.rows; let rowIndex = index;\" [ngClass]=\"row.ngClass\">\n <td class=\"\" *ngIf=\"showCheckboxColumn && gridData?.hasData && checkBoxMode == 1\">\n <div class=\"custom-control custom-switch\" style=\"overflow: initial !important\">\n <input type=\"checkbox\" class=\"custom-control-input\" [id]=\"'customSwitchDataGrid' + rowIndex + tableId\" [(ngModel)]=\"row.selected\" (change)=\"OnRowSelectedChanged(row, rowIndex)\" > \n <label class=\"custom-control-label\" [for]=\"'customSwitchDataGrid' + rowIndex + tableId\"></label> \n </div> \n </td>\n <td class=\"text-center checkbox-column\" *ngIf=\"showCheckboxColumn && gridData?.hasData && checkBoxMode == 0\">\n \n <input type=\"checkbox\" [(ngModel)]=\"row.selected\" (change)=\"OnRowSelectedChanged(row, rowIndex)\" *ngIf=\"checkBoxMode == 0 \" />\n </td>\n <td class=\"action text-center\" *ngIf=\"showActionsColumn\">\n <ng-container \n [ngTemplateOutlet]=\"actionsColumnTemplate\"\n [ngTemplateOutletContext]=\"{\n row: row.model,\n rowIndex: rowIndex\n }\">\n </ng-container>\n </td>\n <td *ngFor=\"let column of columns; let columnIndex = index;\" \n class=\"{{column.dataClasses}}\" \n [ngClass]=\"{\n 'text-center': column.dataAlignment == 1,\n 'text-right': column.dataAlignment == 2\n }\"> \n <span \n [title]=\"column.enableTooltip ? row.columns[columnIndex].value : ''\"\n [innerHtml]=\"row.columns[columnIndex]?.value\"\n (click)=\"HandleColumnClick(row, row.columns[columnIndex].value, rowIndex, column)\">\n </span>\n </td>\n </tr>\n <tr *ngIf=\"showSummaries && HasSummarizableColumns()\" class=\"summaries\">\n <td *ngIf=\"showCheckboxColumn && gridData?.hasData\"></td>\n <td *ngIf=\"showActionsColumn\"></td>\n <td *ngFor=\"let column of columns; let columnIndex = index;\" class=\"{{column.dataClasses}}\" [ngClass]=\"{\n 'text-center': column.dataAlignment == 1,\n 'text-right': column.dataAlignment == 2\n }\"> \n <span *ngIf=\"column.summarizable\">{{column.summaryPrefix}}{{RenderColumnSummary(column) | number:'1.2-2'}}</span>\n </td>\n </tr>\n </tbody>\n <tfoot *ngIf=\"sortApplied && (!gridData || !gridData.hasData)\">\n <tr>\n <td class=\"empty-results text-center p-3\" [attr.colspan]=\"columns?.length + (showActionsColumn ? 1 : 0) + (showCheckboxColumn && gridData?.hasData ? 1 : 0)\">\n <p class=\"mb-0\">{{emptyResultsMessage}}</p>\n </td>\n </tr>\n </tfoot>\n </table>\n\n <div class=\"loading-box\" *ngIf=\"!sortApplied\">\n <spinner></spinner>\n </div>\n </div>\n\n <div class=\"d-flex align-items-center flex-wrap-reverse mt-3\" *ngIf=\"showInfos && gridData?.hasData\">\n <div class=\"d-flex align-items-center flex-wrap-reverse justify-content-center\">\n <div class=\"d-flex align-items-center flex-wrap\">\n <div class=\"export-actions mr-3 my-1\" *ngIf=\"allowExports\">\n <div class=\"btn-group\" dropdown>\n <button dropdownToggle type=\"button\" class=\"btn btn-primary dropdown-toggle\">\n <i class=\"fa fa-external-link\"></i> {{exportButtonLabel}} <span class=\"caret\"></span>\n </button>\n <ul *dropdownMenu class=\"dropdown-menu\" role=\"menu\">\n <li role=\"menuitem\"><a class=\"dropdown-item\" href=\"#\" (click)=\"ExportToExcel($event)\"><i class=\"fa fa-file-excel-o\"></i> Excel</a></li>\n </ul>\n </div>\n </div>\n </div>\n <div class=\"info mr-3 my-1\">\n <span>{{GetInfo()}}</span>\n </div>\n </div>\n \n <div class=\"pagination ml-auto\">\n <pagination #paginator\n [(ngModel)]=\"currentPage\"\n [totalItems]=\"totalItems\"\n [itemsPerPage]=\"itemsPerPage\"\n [boundaryLinks]=\"boundaryLinks\"\n [directionLinks]=\"directionLinks\"\n [maxSize]=\"maxSize\"\n [rotate]=\"rotate\"\n [firstText]=\"firstText\"\n [lastText]=\"lastText\"\n [nextText]=\"nextText\"\n [previousText]=\"previousText\"\n (pageChanged)=\"PageChanged($event)\">\n </pagination>\n </div>\n </div> \n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1 0 auto}.ui-hero-datagrid{position:relative;display:flex;flex-direction:column;flex:1 0 auto}.ui-hero-datagrid table{margin-bottom:0}.ui-hero-datagrid table th{position:relative}.ui-hero-datagrid table th>div>div{flex-shrink:0;-webkit-user-select:none;user-select:none}.ui-hero-datagrid table th .resizer{position:absolute;cursor:col-resize;top:0;right:0;width:6px;height:100%;background:repeating-linear-gradient(45deg,transparent,transparent 2px,rgba(0,0,0,.05) 2px,rgba(0,0,0,.05) 4px)}.ui-hero-datagrid table th:hover .resizer{background:repeating-linear-gradient(45deg,transparent,transparent 2px,rgba(0,0,0,.2) 2px,rgba(0,0,0,.2) 4px)}.ui-hero-datagrid table td,.ui-hero-datagrid table th{overflow:hidden;vertical-align:middle}.ui-hero-datagrid table td>*{word-break:break-word}.ui-hero-datagrid table th.sortable{cursor:pointer}.ui-hero-datagrid table th.checkbox-column input[type=checkbox]{margin:0;width:20px;height:20px;vertical-align:middle}.ui-hero-datagrid table td.checkbox-column input[type=checkbox]{margin:0 auto;width:20px;height:20px;vertical-align:middle}.ui-hero-datagrid table tr.sum