UNPKG

@circe/table

Version:
797 lines (792 loc) 65.2 kB
import { Injectable, EventEmitter, Component, ChangeDetectionStrategy, Renderer2, ViewChild, ViewChildren, Input, Output, HostListener, ElementRef, ChangeDetectorRef, NgModule } from '@angular/core'; import { ToolService, IconsOld, EventsService, BoxModelService, BoxModelModule, EventsModule, ToolModule } from '@circe/core'; import { BehaviorSubject, Subject, isObservable, combineLatest, of, fromEvent } from 'rxjs'; import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling'; import { takeUntil, map, delay, tap, debounceTime } from 'rxjs/operators'; import { SelectComponent, SelectModule } from '@circe/select'; import { PaginationComponent } from '@circe/pagination'; import { CommonModule } from '@angular/common'; import { BadgeModule } from '@circe/badge'; import { FormsModule } from '@angular/forms'; import { FormBehaviorModule } from '@circe/form-behavior'; import { DropdownModule } from '@circe/dropdown'; import { KeyboardEmitterModule } from '@circe/event-controls'; import { SpinnerModule } from '@circe/spinner'; import { TooltipModule } from '@circe/tooltip'; class TableService { constructor() { this.tables = {}; } _checkExists(tableId, columnId, asArray = false) { if (!this.tables[tableId]) { this.tables[tableId] = {}; } if (!this.tables[tableId][columnId]) { this.tables[tableId][columnId] = asArray ? [] : {}; } } addCheckboxData(tableId, rowId, columnId) { if (!this.tables[tableId]) { this.tables[tableId] = {}; } if (!this.tables[tableId][columnId]) { this.tables[tableId][columnId] = []; } this.tables[tableId][columnId].push(rowId); } setRadioData(tableId, rowId, columnId) { this._checkExists(tableId, columnId); this.tables[tableId][columnId] = rowId; } setSelectData(tableId, rowId, columnId, value) { this._checkExists(tableId, columnId); if (!this.tables[tableId][columnId][rowId]) { this.tables[tableId][columnId][rowId] = {}; } this.tables[tableId][columnId][rowId] = value; } deleteCheckboxData(tableId, rowId, columnId) { this._checkExists(tableId, columnId, true); this.tables[tableId][columnId] = this.tables[tableId][columnId].filter((id) => id !== rowId); } getColumnData(tableId, columnId) { const _table = this.tables[tableId]; return _table[columnId] ? _table[columnId] : {}; } } TableService.decorators = [ { type: Injectable } ]; TableService.ctorParameters = () => []; class TableSource { constructor(data, _filter, _paginator, _sorter) { this.totalItems$ = new BehaviorSubject(0); this._data$ = new BehaviorSubject([]); this._filter$ = new BehaviorSubject([]); this._sorter$ = new BehaviorSubject(null); this._paginator$ = new BehaviorSubject(null); this._renderChanges$ = new BehaviorSubject([]); this.cancelStream$ = new Subject(); if (data) { this.data = data; } if (_filter) { this.filter = _filter; } if (_sorter) { this.sorter = _sorter; } if (_paginator) { this.paginator = _paginator; } this._getDataObservable(); } get data() { return this._data$; } set data(data) { var _a; if (data) { if (isObservable(data)) { (_a = this._dataSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this._dataSubscription = data.subscribe((data) => this._data$.next(data)); } else { this._data$.next(data); } } } get filter() { return this._filter$; } set filter(filter) { var _a; if (filter) { if (isObservable(filter)) { (_a = this._filterSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this._filterSubscription = filter.subscribe((filter) => this._filter$.next(filter)); } else { this._filter$.next(filter); } } } get sorter() { return this._sorter$; } set sorter(sorter) { var _a; if (sorter) { if (isObservable(sorter)) { (_a = this._sortSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this._sortSubscription = sorter.subscribe((sort) => this._sorter$.next(sort)); } else { this._sorter$.next(sorter); } } } get paginator() { return this._paginator$; } set paginator(paginator) { var _a; if (paginator) { if (isObservable(paginator)) { (_a = this._pageSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this._pageSubscription = paginator.subscribe((page) => this._paginator$.next(page)); } else { this._paginator$.next(paginator); } } } static sortRows(rows, columnId, order = 'asc') { const _output = rows.map((e) => { return (e[columnId] === undefined) ? Object.assign(Object.assign({}, e), { [columnId]: '' }) : (e[columnId] === 0) ? Object.assign(Object.assign({}, e), { [columnId]: '0' }) : e; }).sort((a, b) => (order === 'asc') ? (a[columnId] > b[columnId] ? 1 : -1) : (a[columnId] < b[columnId] ? 1 : -1)); return _output; } static filterRows(rows, filters) { const _output = rows .filter((row) => { const _filterSuccess = filters.filter((f) => !!f.columns && !!f.value).every((f) => { return f.columns.some((columnId) => { const _value = ToolService.getValueFromMultiLevelObject(row, String(columnId)).toString().toLowerCase(); const _filterValue = f.value.toString().toLowerCase(); return f.searchExactly ? _value === _filterValue : _value.includes(_filterValue); }); }); return _filterSuccess; }); return _output; } _getDataObservable() { var _a; let _dataStream = isObservable(this._data$) ? this._data$ : new BehaviorSubject(this._data$); let _filterStream = isObservable(this._filter$) ? this._filter$ : new BehaviorSubject(this._filter$); let _sortStream = isObservable(this._sorter$) ? this._sorter$ : new BehaviorSubject(this._sorter$); let _pageStream = isObservable(this._paginator$) ? this._paginator$ : new BehaviorSubject(this._paginator$); this.cancelStream$.next(); _dataStream = _dataStream.pipe(takeUntil(this.cancelStream$)); _filterStream = _filterStream.pipe(takeUntil(this.cancelStream$)); _sortStream = _sortStream.pipe(takeUntil(this.cancelStream$)); _pageStream = _pageStream.pipe(takeUntil(this.cancelStream$)); const _filteredData = combineLatest([_dataStream, _filterStream]) .pipe(map(([data, filters]) => { return this._filterRows(data, filters); })); const _orderedData = combineLatest([_filteredData, _sortStream]) .pipe(map(([data, sort]) => { return this._orderRows(data, sort); })); const _paginatedData = combineLatest([_orderedData, _pageStream]) .pipe(map(([data, page]) => { return this._pageRows(data, page); })); (_a = this._renderChangesSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this._renderChangesSubscription = _paginatedData.subscribe((d) => { this._renderChanges$.next(d); }); } _filterRows(data, filters) { if (!(filters === null || filters === void 0 ? void 0 : filters.length)) { this.totalItems$.next(data.length); return data; } const _filteredData = TableSource.filterRows(data, filters); const _actualPage = isObservable(this._paginator$) ? this._paginator$.value : this._paginator$; const _newPage = { pageFirstItem: 0, itemsPerPage: _actualPage === null || _actualPage === void 0 ? void 0 : _actualPage.itemsPerPage }; if (this._paginator$) { this._paginator$.next(_newPage); this.totalItems$.next(_filteredData.length); } return _filteredData; } _orderRows(data, sort) { if (!sort || !sort.columnId || !sort.sortType) { return data; } return [...TableSource.sortRows(data.slice(), sort.columnId, sort.sortType)]; } _pageRows(data, page) { if (!!page && !!page.itemsPerPage && page.pageFirstItem >= 0) { const startIndex = page.pageFirstItem; return data.slice(startIndex, startIndex + (page.itemsPerPage)); } return data; } _isPaginationComponent(obj) { return !!obj && (obj instanceof PaginationComponent || (typeof obj.ngOnInit === 'function' && typeof obj.ngOnChanges === 'function')); } connect() { return this._renderChanges$; } } function _isTableSource(obj) { return !!obj && (obj instanceof TableSource || (typeof obj.connect === 'function')); } class NpaTableConfiguration { constructor(rows$, configModel) { this.tableHeight$ = new BehaviorSubject(''); this._defaultConfiguration = { keyColumnParam: 'id', defaultActionColumnId: 'id', columns: [], minColumnWidth: 50, showHeader: true, sortTable: true, hoverRows: false, truncateTexts: false, emitOnScroll: false }; this._rows$ = rows$; this._processConfiguration(typeof configModel === 'object' ? Object.assign(Object.assign({}, this._defaultConfiguration), configModel) : this._defaultConfiguration); } _processConfiguration(config) { if ('keyColumnParam' in config) { this.keyColumnParam = config.keyColumnParam; } else { throw new Error('You must provide keyColumnParam config in order to get the id from every row.'); } if ('defaultActionColumnId' in config) { this.defaultActionColumnId = config.defaultActionColumnId; } if ('showHeader' in config) { this.showHeader = config.showHeader; } if ('sortTable' in config) { this.sortTable = config.sortTable; } if ('hoverRows' in config) { this.hoverRows = config.hoverRows; } if ('tableHeight' in config) { this.tableHeight$.next(config.tableHeight + 'px'); } if ('minColumnWidth' in config) { this.minColumnWidth = config.minColumnWidth; } if ('truncateTexts' in config) { this.truncateTexts = config.truncateTexts; } if ('actionsConfig' in config) { this.actionsConfigurationModel = config.actionsConfig; } if ('emitOnScroll' in config) { this.emitOnScroll = config.emitOnScroll; } if ('columns' in config) { this.columns = this._processColumnsConfig(config.columns); } const _columnsLength = this.columns.length; this.minRowWidth = (this.minColumnWidth * _columnsLength) + 24 * _columnsLength; } _processColumnsConfig(columns) { const _auxColumns = []; for (const column of columns) { _auxColumns.push(Object.assign(Object.assign({}, column), { sortable: 'sortable' in column ? column.sortable : true })); // this.checkboxColumnsModel[column.id] = { // checkAll: false, // checkNone: true, // model: false // }; } const _columnsWidths = _auxColumns.map((c) => c.columnWidth); this._calculateColumnsWidth(_columnsWidths); // for (const _column of _auxColumns) { // if (_column.type === 'checkbox') { // const _checkboxColumnsModel: NpaTableCheckboxSelection = this.checkboxColumnsModel[_column.id]; // this.checkColumnCheckboxes(_column.id); // _checkboxColumnsModel.model = _checkboxColumnsModel.checkAll || !_checkboxColumnsModel.checkNone; // } // } return _auxColumns; } _calculateColumnsWidth(columnsWidths) { const _showActionsColumn = this.actionsConfigurationModel && !this.actionsConfigurationModel.hideColumn; const _columnsWidths = _showActionsColumn ? [...columnsWidths, this.actionsConfigurationModel.columnWidth] : columnsWidths; const totalPercentage = 100; let gridColumnsWidth = []; let auxPercentage = totalPercentage; let columnWidthsCount = 0; let columnsWithoutWidthCount = 0; for (const _columnWidth of _columnsWidths) { if (_columnWidth && (auxPercentage - _columnWidth) >= 0) { auxPercentage -= _columnWidth; columnWidthsCount++; } else { columnsWithoutWidthCount++; } } if (auxPercentage === totalPercentage) { gridColumnsWidth = new Array(_columnsWidths.length).fill(`${totalPercentage / _columnsWidths.length}%`, 0, _columnsWidths.length); } else if (auxPercentage >= 0) { gridColumnsWidth = _columnsWidths.map((columnWidth) => `${columnWidth !== null && columnWidth !== void 0 ? columnWidth : (auxPercentage / columnsWithoutWidthCount)}%`); } if (this.minColumnWidth) { gridColumnsWidth = gridColumnsWidth.map((width, i) => { const _minWidth = _showActionsColumn && i === gridColumnsWidth.length - 1 ? 16 : this.minColumnWidth; return `minmax(${_minWidth}px, ${width})`; }); } this.columnsWidth = gridColumnsWidth.join(' '); } } class NpaTableActionsConfiguration { constructor(configModel) { this._defaultConfiguration = { dropdownConfig: { elementReference: '' }, actionsType: 'link', columnWidth: 5, showOnHover: false, group: true, hideColumn: false, defaultActionId: '' }; this._processConfiguration(typeof configModel === 'object' ? Object.assign(Object.assign({}, this._defaultConfiguration), configModel) : this._defaultConfiguration); } _processConfiguration(config) { var _a; if ('dropdownConfig' in config) { this.dropdownConfig = Object.assign(Object.assign({}, this.dropdownConfig), config.dropdownConfig); } if ('actionsType' in config) { this.actionsType = config.actionsType; } if ('columnWidth' in config) { this.columnWidth = config.columnWidth; } if ('group' in config) { this.group = config.group; } if ('hideColumn' in config) { this.hideColumn = config.hideColumn; } if ('showOnHover' in config) { this.showOnHover = config.showOnHover; } if ('actions' in config) { this.actions = config.actions; } if ('defaultActionId' in config) { this.defaultActionId = config.defaultActionId; } if (this.group && !((_a = this.dropdownConfig) === null || _a === void 0 ? void 0 : _a.elementRelative)) { throw new Error('If actions are grouped, an elementRelative for dropdown config is required.'); } if (config.actions && !this.group && !this.actionsType) { throw new Error('You must provide a type for actions.'); } } } class TableComponent { constructor(ev, tools, tableService, _renderer) { this.ev = ev; this.tools = tools; this.tableService = tableService; this._renderer = _renderer; this.internalUpdate = new EventEmitter(); this.sortChange = new EventEmitter(); this.scrolledToBottom = new EventEmitter(); this.internalId = ToolService.generateUuid(); this.rows$ = new BehaviorSubject([]); this.checkboxColumnsModel = {}; this.rowsHoverState = []; this.groupActions$ = new BehaviorSubject(false); this.showInternalSpinner$ = new BehaviorSubject(false); this.manualActionsHide$ = new Subject(); this.sort$ = new BehaviorSubject(null); this._originalDataCopy = []; this._componentDestroyed$ = new Subject(); this._iconHandler = new IconsOld(); } get sort() { return this.sort$.value; } set sort(sort) { var _a; (_a = this._sortSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this._sortSubscription = isObservable(sort) ? sort.subscribe(this.sort$) : of(sort).subscribe(this.sort$); } onResize() { this.showInternalSpinner$.next(true); } _setDataStream() { var _a; if (this.data) { if (Array.isArray(this.data)) { this.dataSource$ = of(this.data); } else if (isObservable(this.data)) { this.dataSource$ = this.data; } else if (_isTableSource(this.data)) { this.dataSource$ = this.data.connect(); } else { throw new Error('[TableComponent]: data input must be of type T[], Observable<T[]> or TableSource<T>'); } (_a = this.dataSourceSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this.dataSourceSubscription = this.dataSource$.pipe(takeUntil(this._componentDestroyed$)).subscribe((data) => { var _a; this._originalDataCopy = [...data]; this.rows$.next(this._processRows(data, (_a = this.tableConfiguration) === null || _a === void 0 ? void 0 : _a.columns)); }); this.rows$.pipe(takeUntil(this._componentDestroyed$), delay(1), tap((rows) => { this._setScrollListener(); this._viewPort.checkViewportSize(); })).subscribe(); } } _processRows(rows, columnsConfig) { return columnsConfig ? rows.map((row) => { return columnsConfig.map((c) => this._processColumn(row, c)); }) : []; } _processColumn(rowData, columnConfig) { const column = Object.assign({}, columnConfig); let auxColumn = Object.assign({ sortable: true }, columnConfig); switch (column.type) { case 'checkbox': auxColumn = this._processCheckboxColumn(column, rowData); break; case 'radio': auxColumn = this._processRadioColumn(column); break; case 'select': auxColumn = this._processSelectColumn(column, rowData); break; case 'icon': auxColumn = this._processIconColumn(rowData, column); break; case 'badge': auxColumn = this._processBadgeColumn(rowData, column); break; case 'date': auxColumn = this._processDateColumn(rowData, column); break; default: if ('param' in columnConfig) { auxColumn.value = ToolService.getValueFromMultiLevelObject(rowData, columnConfig.param); } } return auxColumn; } _processCheckboxColumn(columnConfig, rowData) { const _rowId = ToolService.getValueFromMultiLevelObject(rowData, this.tableConfiguration.keyColumnParam); const _checkboxColumn = Object.assign({}, columnConfig); const _tableServiceData = this.tableService.tables[this.id]; const _columnConfigData = _tableServiceData ? _tableServiceData[columnConfig.id] : null; _checkboxColumn.value = !!_columnConfigData && _columnConfigData.includes(_rowId); return _checkboxColumn; } _processRadioColumn(columnConfig) { const _radioColumn = Object.assign({}, columnConfig); const _tableServiceData = this.tableService.tables[this.id]; const _columnConfigData = _tableServiceData ? _tableServiceData[columnConfig.id] : null; _radioColumn.value = _columnConfigData !== null && _columnConfigData !== void 0 ? _columnConfigData : -1; return _radioColumn; } _processSelectColumn(columnConfig, rowData) { const _rowId = ToolService.getValueFromMultiLevelObject(rowData, this.tableConfiguration.keyColumnParam); const _columnConfigIsSet = !!columnConfig.typeConfig; const _selectColumn = Object.assign({}, columnConfig); const _typeConfig = _selectColumn.typeConfig; const _tableServiceData = this.tableService.tables[this.id]; const _columnConfigData = _tableServiceData ? _tableServiceData[columnConfig.id] : null; _selectColumn.selectConfig = Object.assign(Object.assign({ dropdownRelativeElement: 'npa-table__viewport' }, _typeConfig.selectConfig), { size: 'small', setDropdownParentTo: { type: 'id', name: 'npa-table-' + this.internalId } }); if (_columnConfigIsSet) { if ('defaultValue' in _typeConfig) { _selectColumn.value = _typeConfig.defaultValue; } if ('multilevel' in _typeConfig) { _selectColumn.selectConfig = Object.assign(Object.assign({}, _selectColumn.selectConfig), { multiple: _typeConfig.multilevel, multipleSelectionBehavior: 'checkbox' }); _selectColumn.value = _columnConfigData ? _columnConfigData[_rowId] : []; } else { _selectColumn.value = _columnConfigData ? _columnConfigData[_rowId] : ''; } if ('placeholder' in _typeConfig) { _selectColumn.selectConfig = Object.assign(Object.assign({}, _selectColumn.selectConfig), { placeholder: _typeConfig.placeholder }); } if (_selectColumn.selectConfig.multiple && 'multilevelButtonLabel' in _typeConfig) { _selectColumn.selectConfig = Object.assign(Object.assign({}, _selectColumn.selectConfig), { confirmButtonLabel: _typeConfig.multilevelButtonLabel }); } } return _selectColumn; } _processIconColumn(rowData, columnConfig) { const _columnConfigIsSet = !!columnConfig.typeConfig; const _selectColumn = Object.assign({}, columnConfig); const _typeConfig = _selectColumn.typeConfig; if (_columnConfigIsSet) { if ('icon' in _typeConfig) { _selectColumn.icon = this._getIcon(rowData, columnConfig); } if ('onlyIcon' in _typeConfig) { _selectColumn.onlyIcon = _typeConfig.onlyIcon; } if ('param' in columnConfig) { _selectColumn.value = ToolService.getValueFromMultiLevelObject(rowData, columnConfig.param); } } return _selectColumn; } _processBadgeColumn(rowData, columnConfig) { const _columnConfigIsSet = !!columnConfig.typeConfig; const _badgeColumn = Object.assign({}, columnConfig); const _typeConfig = _badgeColumn.typeConfig; if (_columnConfigIsSet) { if ('type' in _typeConfig) { _badgeColumn.badgeType = this._getBadgeType(rowData, columnConfig); } if ('param' in columnConfig) { _badgeColumn.value = ToolService.getValueFromMultiLevelObject(rowData, columnConfig.param); } } return _badgeColumn; } _processDateColumn(rowData, columnConfig) { const _columnConfigIsSet = !!columnConfig.typeConfig; const _dateColumn = Object.assign({}, columnConfig); if (_columnConfigIsSet) { if ('param' in columnConfig) { _dateColumn.value = new Date(ToolService.getValueFromMultiLevelObject(rowData, columnConfig.param)); } } return _dateColumn; } _getBadgeType(row, column) { const _typeConfig = column.typeConfig; const _badgeType = _typeConfig.type; if (_badgeType) { return (typeof _badgeType === 'function' ? _badgeType(row) : _badgeType); } return ''; } _getIcon(row, column) { let auxIcon = { classes: '' }; const _typeConfig = column.typeConfig; const _icon = _typeConfig.icon; if (_icon) { auxIcon = (typeof _icon === 'function' ? _icon(row) : _icon); } return this._iconHandler.getIcon(auxIcon); } _getTableValue() { return this.rows$.value.map(this.getRowValue.bind(this)); } _hideAllDropdowns() { this.manualActionsHide$.next(); if (this.selects.length) { for (const _select of this.selects) { if (_select.showDropdown) { _select.setDropdown(); } } } } _setScrollListener() { var _a; if (!!this._viewPort) { (_a = this._scrollSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this._scrollSubscription = fromEvent(this._viewPort.getElementRef().nativeElement, 'scroll') .pipe(tap(() => this._hideAllDropdowns()), debounceTime(300), takeUntil(this._componentDestroyed$)).subscribe(this.checkScroll.bind(this)); } } _setResizeListener() { fromEvent(window, 'resize') .pipe(tap(() => this.manualActionsHide$.next()), debounceTime(300), takeUntil(this._componentDestroyed$)) .subscribe(() => { this.showInternalSpinner$.next(false); }); this.showInternalSpinner$.pipe(takeUntil(this._componentDestroyed$), delay(1)) .subscribe(() => { if (this._viewPort) { this._viewPort.checkViewportSize(); } }); } _processConfiguration(config) { this.tableConfiguration = new NpaTableConfiguration(this.rows$, config); this.tableActionsConfiguration = new NpaTableActionsConfiguration(this.tableConfiguration.actionsConfigurationModel); this._checkBiggerTableActions(this.tableActionsConfiguration.group); } ngOnInit() { this._processConfiguration(this.config); this._setDataStream(); } ngAfterViewInit() { this._setResizeListener(); } ngOnChanges(changes) { var _a, _b, _c, _d; if (this.hotRender && (((_a = changes.config) === null || _a === void 0 ? void 0 : _a.currentValue) && ((_b = changes.config) === null || _b === void 0 ? void 0 : _b.previousValue))) { this._processConfiguration((_c = changes.config) === null || _c === void 0 ? void 0 : _c.currentValue); this._setDataStream(); } if ((_d = changes.data) === null || _d === void 0 ? void 0 : _d.currentValue) { this._setDataStream(); this._checkBiggerTableActions(this.groupActions$.value); } } checkColumnCheckboxes(columnId) { const _rows = [...this.rows$.value]; const columnValues = _rows.map((r) => { var _a; return !!((_a = r.find((c) => c.id === columnId)) === null || _a === void 0 ? void 0 : _a.value); }); if (!this.checkboxColumnsModel[columnId]) { this.checkboxColumnsModel[columnId] = { checkAll: false, checkNone: true, model: false }; } this.checkboxColumnsModel[columnId].checkAll = !!_rows.length && columnValues && (columnValues === null || columnValues === void 0 ? void 0 : columnValues.every((v) => v)); this.checkboxColumnsModel[columnId].checkNone = columnValues === null || columnValues === void 0 ? void 0 : columnValues.every((v) => !v); this.checkboxColumnsModel[columnId].model = this.checkboxColumnsModel[columnId].checkAll || !this.checkboxColumnsModel[columnId].checkNone; } sortTableRows(column) { if (this.tableConfiguration.sortTable && column.sortable && column.columnName) { const { sortType, columnId } = this.sort$.value; const _newSortType = (sortType === 'desc' || columnId !== column.id) ? 'asc' : 'desc'; this.sort$.next({ columnId: column.id, sortType: _newSortType }); this.sortChange.emit({ columnId: column.id, sortType: _newSortType }); } } updateRadioColumn(columnId, newValue) { const _rows = [...this.rows$.value]; _rows.forEach((row, rowIndex) => { const _column = row.find((r) => r.id === columnId); _column.value = newValue; if (_column.rowId === newValue) { const _row = this.getRowValue(row, rowIndex); const _rowId = ToolService.getValueFromMultiLevelObject(_row.npaTableDataSource, this.tableConfiguration.keyColumnParam); this.tableService .setRadioData(this.id, _rowId, _column.id); } }); this.internalUpdate.emit(this._getTableValue()); } updateCheckboxColumn(column, row, rowIndex, newValue, bypassCheck) { column.value = newValue; if (!this.checkboxColumnsModel[column.id]) { this.checkboxColumnsModel[column.id] = { checkAll: false, checkNone: true, model: false }; } const _rows = [...this.rows$.value]; const _row = this.getRowValue(row, rowIndex); const _rowId = ToolService.getValueFromMultiLevelObject(_row.npaTableDataSource, this.tableConfiguration.keyColumnParam); const columnValues = _rows.map((r) => !!r.find((c) => c.id === column.id).value); this.checkboxColumnsModel[column.id].checkAll = columnValues.every((v) => v); this.checkboxColumnsModel[column.id].checkNone = columnValues.every((v) => !v); // this.checkboxColumnsModel[column.id].model = this.checkboxColumnsModel[column.id].checkAll || !this.checkboxColumnsModel[column.id].checkNone; if (newValue) { this.tableService.addCheckboxData(this.id, _rowId, column.id); } else { this.tableService.deleteCheckboxData(this.id, _rowId, column.id); } if (!bypassCheck) { this.checkColumnCheckboxes(column.id); } this.internalUpdate.emit(this._getTableValue()); } updateColumnValue(column, row, rowIndex, newValue) { const _row = this.getRowValue(row, rowIndex); const _rowId = ToolService.getValueFromMultiLevelObject(_row.npaTableDataSource, this.tableConfiguration.keyColumnParam); column.value = newValue; this.tableService .setSelectData(this.id, _rowId, column.id, newValue); this.internalUpdate.emit(this._getTableValue()); } linkAction(column, row, rowIndex) { const _typeConfig = column.typeConfig; if (_typeConfig === null || _typeConfig === void 0 ? void 0 : _typeConfig.linkAction) { _typeConfig.linkAction(this.getRowValue(row, rowIndex)); } } setColumnCheckboxes(columnId) { const _rows = [...this.rows$.value]; this.checkboxColumnsModel[columnId].model = !this.checkboxColumnsModel[columnId].model; _rows.forEach((row, rowIndex) => { const _column = row.find((c) => c.id === columnId); this.updateCheckboxColumn(_column, row, rowIndex, this.checkboxColumnsModel[columnId].model, true); }); this.checkColumnCheckboxes(columnId); this.internalUpdate.emit(this._getTableValue()); } rowHover(columnIndex) { this.rowsHoverState = new Array(this.rowsHoverState.length).fill(false); this.rowsHoverState[columnIndex] = true; } tableMouseLeave() { this.rowsHoverState = new Array(this.rowsHoverState.length).fill(false); } rowMouseLeave(rowIndex) { this.rowsHoverState = [...this.rowsHoverState.slice(0, rowIndex), false, ...this.rowsHoverState.slice(rowIndex + 1)]; } checkScroll() { const _viewPortElement = this._viewPort.getElementRef().nativeElement; const _bodyHasScroll = _viewPortElement.offsetHeight < _viewPortElement.scrollHeight; if (this._viewPort && this.tableConfiguration.emitOnScroll) { const _viewPort = this._viewPort.getElementRef().nativeElement; if (_bodyHasScroll && _viewPort.scrollTop + _viewPort.offsetHeight >= _viewPort.scrollHeight) { this.scrolledToBottom.emit(); } } } getRowValue(row, rowIndex) { var _a; const _originalRow = (_a = this._originalDataCopy[rowIndex]) !== null && _a !== void 0 ? _a : {}; const _rowValue = { npaTableDataSource: Object.assign({}, _originalRow) }; for (const column of row) { if (column.id !== 'npa-table-actions-column') { _rowValue[column.id] = column.type === 'radio' ? (column.value === rowIndex) : column.value; } } return Object.assign({}, _rowValue); } _checkBiggerTableActions(group) { var _a, _b, _c; let _biggerTableActions; const _tableActionsComponents = this.tableActions ? Array.from(this.tableActions) : []; for (const _tableActionsComponent of _tableActionsComponents) { if (!_biggerTableActions || ((_a = _tableActionsComponent.actionsContainer) === null || _a === void 0 ? void 0 : _a.nativeElement.scrollWidth) > _biggerTableActions.scrollWidth) { _biggerTableActions = (_b = _tableActionsComponent.actionsContainer) === null || _b === void 0 ? void 0 : _b.nativeElement; } } const _tableActionsComponentParent = (_c = _tableActionsComponents[0]) === null || _c === void 0 ? void 0 : _c.el.nativeElement.parentNode; if (!group && _biggerTableActions && _biggerTableActions.scrollWidth >= (_tableActionsComponentParent === null || _tableActionsComponentParent === void 0 ? void 0 : _tableActionsComponentParent.offsetWidth)) { this.groupActions$.next(true); } else { this.groupActions$.next(group); } } ngOnDestroy() { this._componentDestroyed$.next(); this._componentDestroyed$.complete(); this._componentDestroyed$.unsubscribe(); } } TableComponent.decorators = [ { type: Component, args: [{ selector: 'npa-table', template: "<div class=\"npa-table\" #table [id]=\"'npa-table-' + internalId\" [style.height]=\"tableConfiguration?.tableHeight$ | async\">\n <div\n class=\"npa-table__header\"\n #tableHeader\n *ngIf=\"tableConfiguration?.showHeader\"\n [ngStyle]=\"{ 'min-width': table?.offsetWidth < tableConfiguration.minRowWidth ? tableConfiguration.minRowWidth + 'px' : 'unset'}\"\n [style]=\"{'grid-template-columns': tableConfiguration.columnsWidth}\">\n <div\n class=\"npa-table__header-cell npa-table__header-cell--checkbox\"\n *ngFor=\"let column of tableConfiguration.columns; trackBy: tools.identifier;\"\n [ngClass]=\"{'sort': tableConfiguration.sortTable && column.sortable && column.columnName}\">\n <ng-container *ngIf=\"column.type === 'checkbox' && column.typeConfig.checkboxInHeader\">\n <input\n class=\"npa-selection--vertical\"\n type=\"checkbox\"\n [id]=\"column.id + '-check-all'\"\n [name]=\"column.id + '-check-all'\"\n [ngClass]=\"{\n 'npa-checkbox--indeterminate': (!checkboxColumnsModel[column.id]?.checkAll) && !checkboxColumnsModel[column.id]?.checkNone\n }\"\n [checked]=\"(checkboxColumnsModel[column.id]?.checkAll && !checkboxColumnsModel[column.id]?.checkNone) || checkboxColumnsModel[column.id]?.model\"\n [ngModel]=\"checkboxColumnsModel[column.id]?.model\"\n (ngModelChange)=\"setColumnCheckboxes(column.id)\">\n <label [for]=\"column.id + '-check-all'\"></label>\n </ng-container>\n <span\n class=\"npa-tooltip\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [showWhenTruncated]=\"true\"\n [title]=\"column.columnName\"\n (click)=\"sortTableRows(column)\">\n {{column.columnName}}\n </span>\n <i\n class=\"npa-icon\"\n *ngIf=\"tableConfiguration.sortTable && column.sortable && sort$.value?.sortType && sort$.value?.columnId === column.id\"\n [ngClass]=\"sort$.value.sortType === 'asc' ? 'icon-arrow-up' : 'icon-arrow-down'\"\n (click)=\"sortTableRows(column)\">\n </i>\n </div>\n <div class=\"npa-table__header-cell npa-table__header-cell--checkbox\" *ngIf=\"tableActionsConfiguration && !tableActionsConfiguration.hideColumn\"></div>\n </div>\n <div class=\"npa-table__body--overlay\" *ngIf=\"showSpinner || (showInternalSpinner$ | async)\">\n <div class=\"npa-table__spinner-container\">\n <npa-spinner></npa-spinner>\n </div>\n </div>\n <div\n class=\"npa-table__body\"\n #tableBody\n [ngClass]=\"{'hide': showSpinner || (showInternalSpinner$ | async)}\"\n (mouseleave)=\"tableMouseLeave()\">\n <cdk-virtual-scroll-viewport\n class=\"npa-table__viewport\"\n [ngStyle]=\"{ 'min-width': (table?.offsetWidth < tableConfiguration.minRowWidth) ? tableConfiguration.minRowWidth + 'px' : 'unset'}\"\n [ngClass]=\"{'hide': (rows$ | async)?.length < 1}\"\n [itemSize]=\"41\">\n <div\n class=\"npa-table__row\"\n #tableRow\n *cdkVirtualFor=\"let row of (rows$ | async); trackBy: tools.identifier; let rowIndex = index\"\n [ngClass]=\"{'hover': tableConfiguration.hoverRows}\"\n [style]=\"{'grid-template-columns': tableConfiguration.columnsWidth}\"\n (mouseenter)=\"rowHover(rowIndex)\"\n (mouseleave)=\"rowMouseLeave(rowIndex)\">\n <div\n class=\"npa-table__cell\"\n *ngFor=\"let column of row; trackBy: tools.identifier;\" [id]=\"column.id\">\n <ng-container *ngIf=\"!column.type\">\n <span\n class=\"npa-table__cell-value npa-tooltip npa-tooltip--small npa-tooltip--light\"\n *ngIf=\"(!rowsHoverState[rowIndex] || rowsHoverState && column.id !== tableConfiguration.defaultActionColumnId) || !defaultAction\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [showWhenTruncated]=\"true\"\n [title]=\"column.value\">\n <ng-container *ngIf=\"!!column.param && (!!column.value || column.value === 0)\">{{column.value}}</ng-container>\n <ng-container *ngIf=\"!!column.param && !column.value && column.value !== 0\">{{'-'}}</ng-container>\n </span>\n <a\n class=\"npa-table__cell-value npa-link npa-tooltip npa-tooltip--small npa-tooltip--light\"\n *ngIf=\"rowsHoverState[rowIndex] && column.id === tableConfiguration.defaultActionColumnId && defaultAction\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [title]=\"tableConfiguration.truncateTexts ? column.value : defaultAction.label\"\n [showWhenTruncated]=\"true\"\n (click)=\"defaultAction.callback(getRowValue(row, rowIndex))\">\n <ng-container *ngIf=\"!!column.param && (!!column.value || column.value === 0)\">{{column.value}}</ng-container>\n <ng-container *ngIf=\"!!column.param && !column.value && column.value !== 0\">{{'-'}}</ng-container>\n </a>\n </ng-container>\n <ng-container *ngIf=\"column.type === 'date'\">\n <span\n class=\"npa-table__cell-value npa-tooltip npa-tooltip--small npa-tooltip--light\"\n *ngIf=\"(!rowsHoverState[rowIndex] || rowsHoverState && column.id !== tableConfiguration.defaultActionColumnId) || !defaultAction\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [showWhenTruncated]=\"true\"\n [title]=\"column.value | date:(column.typeConfig?.dateMask || 'MM/dd/yyyy')\">\n {{column.value ? (column.value | date:(column.typeConfig?.dateMask || 'MM/dd/yyyy')) : '-'}}\n </span>\n <a\n class=\"npa-table__cell-value npa-link npa-tooltip npa-tooltip--small npa-tooltip--light\"\n *ngIf=\"rowsHoverState[rowIndex] && column.id === tableConfiguration.defaultActionColumnId && defaultAction\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [title]=\"tableConfiguration.truncateTexts ? (column.value | date:'MM/dd/yyyy') : defaultAction.label\"\n [showWhenTruncated]=\"true\"\n (click)=\"defaultAction.callback(getRowValue(row, rowIndex))\">\n {{column.value ? (column.value | date:'MM/dd/yyyy') : '-'}}\n </a>\n </ng-container>\n <ng-container *ngIf=\"column.type === 'checkbox'\">\n <input\n class=\"npa-selection--vertical npa-selection--no-label\"\n type=\"checkbox\"\n [id]=\"column.id + '-' + rowIndex\"\n [name]=\"column.id + '-' + rowIndex\"\n [ngModel]=\"column.value || checkboxColumnsModel[column.id]?.checkAll\"\n (ngModelChange)=\"updateCheckboxColumn(column, row, rowIndex, $event)\">\n <label [for]=\"column.id + '-' + rowIndex\">{{column.typeConfig?.label}}</label>\n </ng-container>\n <ng-container *ngIf=\"column.type === 'radio'\">\n <input\n type=\"radio\"\n class=\"npa-selection--no-label\"\n [attr.id]=\"column.id + '-' + rowIndex\"\n [name]=\"column.id\"\n [value]=\"column.rowId\"\n [ngModel]=\"column.value\"\n (ngModelChange)=\"updateRadioColumn(column.id, column.rowId)\">\n <label [attr.for]=\"column.id + '-' + rowIndex\">{{column.typeConfig?.label}}</label>\n </ng-container>\n <ng-container *ngIf=\"column.type === 'icon'\">\n <span\n class=\"npa-table__cell-value npa-tooltip npa-tooltip--small npa-tooltip--light\"\n *ngIf=\"!column.onlyIcon && ((!rowsHoverState[rowIndex] || rowsHoverState && column.id !== tableConfiguration.defaultActionColumnId) || !defaultAction)\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [showWhenTruncated]=\"true\"\n [title]=\"column.value\">\n <i *ngIf=\"column.icon\" [ngClass]=\"column.icon\"></i>\n <ng-container *ngIf=\"column.param && column.value\">{{column.value}}</ng-container>\n <ng-container *ngIf=\"column.param && !column.value\">{{'-'}}</ng-container>\n </span>\n <a\n class=\"npa-table__cell-value npa-link npa-tooltip npa-tooltip--small npa-tooltip--light\"\n *ngIf=\"rowsHoverState[rowIndex] && column.id === tableConfiguration.defaultActionColumnId && defaultAction\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [title]=\"tableConfiguration.truncateTexts ? column.value : defaultAction.label\"\n [showWhenTruncated]=\"true\"\n (click)=\"defaultAction.callback(getRowValue(row, rowIndex))\">\n <i *ngIf=\"column.icon\" [ngClass]=\"column.icon\"></i>\n <ng-container *ngIf=\"column.param && column.value\">{{column.value}}</ng-container>\n <ng-container *ngIf=\"column.param && !column.value\">{{'-'}}</ng-container>\n </a>\n </ng-container>\n <ng-container *ngIf=\"column.type === 'badge'\">\n <div class=\"npa-badge npa-badge--alone npa-badge--x-small\" [ngClass]=\"'npa-badge--' + column.badgeType\">\n <div class=\"npa-badge__box\"></div>\n </div>\n <span\n class=\"npa-table__cell-value npa-tooltip npa-tooltip--small npa-tooltip--light npa-color--critical\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [showWhenTruncated]=\"true\"\n [title]=\"column.value\">\n <ng-container *ngIf=\"column.param && column.value\">{{column.value}}</ng-container>\n <ng-container *ngIf=\"column.param && !column.value\">{{'-'}}</ng-container>\n </span>\n </ng-container>\n <ng-container *ngIf=\"column.type === 'link'\">\n <a\n class=\"npa-table__cell-value npa-link\"\n *ngIf=\"!!column.value\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n (click)=\"linkAction(column, row, rowIndex)\">\n {{column.typeConfig?.label ? column.typeConfig.label : column.value}}\n </a>\n <span\n class=\"npa-table__cell-value npa-tooltip npa-tooltip--small npa-tooltip--light npa-color--critical\"\n *ngIf=\"!column.value\"\n [ngClass]=\"{ 'truncate-text': tableConfiguration.truncateTexts }\"\n [showWhenTruncated]=\"true\"\n [title]=\"column.value\">-</span>\n </ng-container>\n <ng-container *ngIf=\"column.type === 'select'\">\n <label class=\"npa-label\" [for]=\"column.id + '-' + rowIndex\"></label>\n <npa-select\n [id]=\"column.id + '-' + rowIndex\"\n [config]=\"column.selectConfig\"\n [options]=\"column.typeConfig.options\"\n [ngModel]=\"column.value\"\n (ngModelChange)=\"updateColumnValue(column, row, rowIndex, $event)\">\n </npa-select>\n </ng-container>\n </div>\n <div\n class=\"npa-table__cell\" [class.hide]=\"tableActionsConfiguration.hideColumn\">\n <npa-table-actions\n #tableActions\n *ngIf=\"tableActionsConfiguration?.actions\"\n [class.hide]=\"tableActionsConfiguration.showOnHover && !rowsHoverState[rowIndex]\"\n [hotRender]=\"true\"\n [manualHideDropdown]=\"manualActionsHide$\"\n [isHoveringRow]=\"rowsHoverState[rowIndex]\"\n [tableRow]=\"row\"\n [rowData]=\"getRowValue(row, rowIndex)\"\n [group]=\"(groupActions$ | async)\"\n [actions]=\"tableActionsConfiguration.actions\"\n [setDropdownParentTo]=\"{ type: 'id', name: 'npa-table-' + internalId }\"\n [dropdownConfig]=\"tableActionsConfiguration.dropdownConfig\"\n [actionsType]=\"tableActionsConfiguration.actionsType\"\n [defaultActionId]=\"tableActionsConfiguration.defaultActionId\"\n (defaultAction)=\"defaultAction = $event\"\n (selectedOption)=\"$event.callback(getRowValue(row, rowIndex))\">\n </npa-table-actions>\n </div>\n </div>\n <div class=\"npa-table__row--spinner\" *ngIf=\"showLoadOnScrollSpinner\">\n <npa-spinner class=\"npa-spinner--20\"></npa-spinner>\n </div>\n </cdk-virtual-scroll-viewport>\n\n <div\n class=\"npa-table__body--overlay\"\n *ngIf=\"!((rows$ | async)?.length) && !showSpinner && (showInternalSpinner$ | async) === false\">\n <ng-content></ng-content>\n </div>\n </div>\n</div>\n", changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--npa-table-default-height:fit-content;--npa-table-default-column-gap:24px;--npa-table-default-column-padding:0 12px;--npa-table-header-default-height:40px;--npa-table-header-default-border-width:0 0 1px 0;--npa-table-header-default-border-style:solid;--npa-table-header-default-border-color:gray;--npa-table-header-cell-default-align:center;--npa-table-header-cell-default-justify:normal;--npa-table-header-cell-default-icon-size:12px;--npa-table-header-cell-default-icon-spacing:8px;--npa-table-header-cell-default-text-transform:uppercase;--npa-table-header-cell-default-color:gray;--npa-table-header-cell-default-icon-color:gray;--npa-table-body-default-height:calc(100% - var(--npa-table-header-default-height) - 1px);--npa-table-body-spinner-top-spacing:40px;--npa-table-row-default-height:40px;--npa-table-row-default-background-color:#fff;--npa-table-row-default-border-width:0 0 1px 0;--npa-table-row-default-border-style:solid;--npa-table-row-default-border-color:#d3d3d3;--npa-table-row-default-hover-background-color:#add8e6;--npa-table-row-default-hover-border-width:0 0 1px 0;--npa-table-row-default-hover-border-style:solid;--npa-table-row-default-hover-border-color:#d3d3d3;--npa-table-row-default-spinner-container-height:40px;--npa-table-row-default-spinner-padding:12px;--npa-table-row-cell-default-align:center;--npa-table-row-cell-default-justify:normal;--npa-table-row-cell-default-icon-spacing:8px;--npa-table-row-cell-default-color:#000}:host .npa-table{height:var(--npa-table-default-height);overflow-x:auto}:host .npa-table .npa-table__header{display:grid;grid-column-gap:var(--npa-table-default-column-gap);padding:var(--npa-table-default-column-padding);border:var(--npa-table-header-default-border-style) var