UNPKG

@angular-customised/ngx-table-custom-sort

Version:

Angular easy table

488 lines 151 kB
import { moveItemInArray } from '@angular/cdk/drag-drop'; import { ChangeDetectionStrategy, Component, ContentChild, EventEmitter, HostListener, Input, Output, TemplateRef, ViewChild, } from '@angular/core'; import { API, Event } from '../..'; import { DefaultConfigService } from '../../services/config-service'; import { GroupRowsService } from '../../services/group-rows.service'; import { StyleService } from '../../services/style.service'; import { Subject } from 'rxjs'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { filter, takeUntil, throttleTime } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "@angular/cdk/scrolling"; import * as i2 from "../../services/style.service"; import * as i3 from "@angular/common"; import * as i4 from "@angular/cdk/drag-drop"; import * as i5 from "../pagination/pagination.component"; import * as i6 from "../thead/thead.component"; import * as i7 from "ngx-pagination"; import * as i8 from "../../pipes/search-pipe"; import * as i9 from "../../pipes/render-pipe"; import * as i10 from "../../pipes/global-search-pipe"; import * as i11 from "../../pipes/sort.pipe"; export class BaseComponent { onContextMenuClick(targetElement) { if (this.contextMenu && !this.contextMenu.nativeElement.contains(targetElement)) { this.rowContextMenuPosition = { top: null, left: null, value: null, }; } } constructor(cdr, scrollDispatcher, styleService) { this.cdr = cdr; this.scrollDispatcher = scrollDispatcher; this.styleService = styleService; this.unsubscribe = new Subject(); this.filterCount = -1; this.filteredCountSubject = new Subject(); this.tableClass = null; this.grouped = []; this.isSelected = false; this.page = 1; this.count = 0; this.sortState = new Map(); this.sortKey = null; this.rowContextMenuPosition = { top: null, left: null, value: null, }; this.sortBy = { key: '', order: 'asc', }; this.selectedDetailsTemplateRowId = new Set(); this.selectedCheckboxes = new Set(); this.id = 'table'; this.event = new EventEmitter(); this.isAllSortEnabled = false; this.filteredCountSubject.pipe(takeUntil(this.unsubscribe)).subscribe((count) => { setTimeout(() => { this.filterCount = count; this.cdr.detectChanges(); }); }); } ngOnInit() { if (!this.columns) { console.error('[columns] property required!'); } if (this.configuration) { this.config = this.configuration; } else { this.config = DefaultConfigService.config; } this.limit = this.config.rows; if (this.groupRowsBy) { this.grouped = GroupRowsService.doGroupRows(this.data, this.groupRowsBy); } this.doDecodePersistedState(); } ngOnDestroy() { this.unsubscribe.next(); this.unsubscribe.complete(); } ngAfterViewInit() { const throttleValue = this.config.infiniteScrollThrottleTime ? this.config.infiniteScrollThrottleTime : 200; this.scrollDispatcher .scrolled() .pipe(throttleTime(throttleValue), filter((event) => { return (!!event && this.viewPort && this.viewPort.getRenderedRange().end === this.viewPort.getDataLength()); }), takeUntil(this.unsubscribe)) .subscribe(() => { this.emitEvent(Event.onInfiniteScrollEnd, null); }); } ngOnChanges(changes) { const { configuration, data, pagination, groupRowsBy } = changes; this.toggleRowIndex = changes.toggleRowIndex; if (configuration && configuration.currentValue) { this.config = configuration.currentValue; } if (data && data.currentValue) { this.doApplyData(data); } if (pagination && pagination.currentValue) { const { count, limit, offset } = pagination.currentValue; this.count = count; this.limit = limit; this.page = offset; } if (groupRowsBy && groupRowsBy.currentValue) { this.grouped = GroupRowsService.doGroupRows(this.data, this.groupRowsBy); } if (this.toggleRowIndex && this.toggleRowIndex.currentValue) { const row = this.toggleRowIndex.currentValue; this.collapseRow(row.index); } } orderBy(column) { if (typeof column.orderEnabled !== 'undefined' && !column.orderEnabled) { return; } this.sortKey = column.key; if (!this.config.orderEnabled || this.sortKey === '') { return; } this.setColumnOrder(column); if (!this.config.orderEventOnly && !column.orderEventOnly) { this.sortBy.key = this.sortKey; this.sortBy.order = this.sortState.get(this.sortKey); } else { this.sortBy.key = ''; this.sortBy.order = ''; } if (!this.config.serverPagination) { this.data = [...this.data]; this.sortBy = { ...this.sortBy }; } const value = { key: this.sortKey, order: this.sortState.get(this.sortKey), }; this.emitEvent(Event.onOrder, value); } onClick($event, row, key, colIndex, rowIndex) { if (this.config.selectRow) { this.selectedRow = rowIndex; } if (this.config.selectCol && `${colIndex}`) { this.selectedCol = colIndex; } if (this.config.selectCell && `${colIndex}`) { this.selectedRow = rowIndex; this.selectedCol = colIndex; } if (this.config.clickEvent) { const value = { event: $event, row, key, rowId: rowIndex, colId: colIndex, }; this.emitEvent(Event.onClick, value); } } onDoubleClick($event, row, key, colIndex, rowIndex) { const value = { event: $event, row, key, rowId: rowIndex, colId: colIndex, }; this.emitEvent(Event.onDoubleClick, value); } onCheckboxSelect($event, row, rowIndex) { const value = { event: $event, row, rowId: rowIndex, }; this.emitEvent(Event.onCheckboxSelect, value); } onRadioSelect($event, row, rowIndex) { const value = { event: $event, row, rowId: rowIndex, }; this.emitEvent(Event.onRadioSelect, value); } onSelectAll() { this.isSelected = !this.isSelected; this.emitEvent(Event.onSelectAll, this.isSelected); } onSearch($event) { if (!this.config.serverPagination) { this.term = $event; } this.emitEvent(Event.onSearch, $event); } onGlobalSearch(value) { if (!this.config.serverPagination) { this.globalSearchTerm = value; } this.emitEvent(Event.onGlobalSearch, value); } onPagination(pagination) { this.page = pagination.page; this.limit = pagination.limit; this.config.rows = pagination.limit; this.emitEvent(Event.onPagination, pagination); } toggleCheckbox(rowIndex) { this.selectedCheckboxes.has(rowIndex) ? this.selectedCheckboxes.delete(rowIndex) : this.selectedCheckboxes.add(rowIndex); } collapseRow(rowIndex) { if (this.selectedDetailsTemplateRowId.has(rowIndex)) { this.selectedDetailsTemplateRowId.delete(rowIndex); this.emitEvent(Event.onRowCollapsedHide, rowIndex); } else { this.selectedDetailsTemplateRowId.add(rowIndex); this.emitEvent(Event.onRowCollapsedShow, rowIndex); } } doDecodePersistedState() { if (!this.config.persistState) { return; } const pagination = localStorage.getItem(Event.onPagination); const sort = localStorage.getItem(Event.onOrder); const search = localStorage.getItem(Event.onSearch); if (pagination) { this.onPagination(JSON.parse(pagination)); } if (sort) { const { key, order } = JSON.parse(sort); this.bindApi({ type: API.sortBy, value: { column: key, order }, }); } if (search) { this.bindApi({ type: API.setInputValue, value: JSON.parse(search), }); } } isRowCollapsed(rowIndex) { if (this.config.collapseAllRows) { return true; } return this.selectedDetailsTemplateRowId.has(rowIndex); } get loadingHeight() { const table = document.getElementById(this.id); if (table && table.rows && table.rows.length > 3) { const searchEnabled = this.config.searchEnabled ? 1 : 0; const headerEnabled = this.config.headerEnabled ? 1 : 0; const borderTrHeight = 1; const borderDivHeight = 2; return ((table.rows.length - searchEnabled - headerEnabled) * (table.rows[3].offsetHeight - borderTrHeight) - borderDivHeight); } return 30; } get arrowDefinition() { return this.config.showDetailsArrow || typeof this.config.showDetailsArrow === 'undefined'; } onRowContextMenu($event, row, key, colIndex, rowIndex) { if (!this.config.showContextMenu) { return; } $event.preventDefault(); const value = { event: $event, row, key, rowId: rowIndex, colId: colIndex, }; this.rowContextMenuPosition = { top: `${$event.pageY - 10}px`, left: `${$event.pageX - 10}px`, value, }; this.emitEvent(Event.onRowContextMenu, value); } doApplyData(data) { const order = this.columns.find((c) => !!c.orderBy); if (order) { this.sortState.set(this.sortKey, order.orderBy === 'asc' ? 'desc' : 'asc'); this.orderBy(order); } else { this.data = [...data.currentValue]; } } onDragStart(event) { this.emitEvent(Event.onReorderStart, event); } onDrop(event) { this.emitEvent(Event.onRowDrop, event); moveItemInArray(this.data, event.previousIndex, event.currentIndex); } // DO NOT REMOVE. It is called from parent component. See src/app/demo/api-doc/api-doc.component.ts apiEvent(event) { return this.bindApi(event); } /* eslint-disable */ bindApi(event) { switch (event.type) { case API.rowContextMenuClicked: this.rowContextMenuPosition = { top: null, left: null, value: null, }; break; case API.toggleRowIndex: this.collapseRow(event.value); break; case API.toggleCheckbox: this.toggleCheckbox(event.value); break; case API.setInputValue: if (this.config.searchEnabled) { event.value.forEach((input) => { const element = document.getElementById(`search_${input.key}`); if (!element) { console.error(`Column '${input.key}' not available in the DOM. Have you misspelled a name?`); } else { element.value = input.value; } }); } this.onSearch(event.value); this.cdr.markForCheck(); break; case API.onGlobalSearch: this.onGlobalSearch(event.value); this.cdr.markForCheck(); break; case API.setRowClass: if (Array.isArray(event.value)) { event.value.forEach((val) => this.styleService.setRowClass(val)); break; } this.styleService.setRowClass(event.value); this.cdr.markForCheck(); break; case API.setCellClass: if (Array.isArray(event.value)) { event.value.forEach((val) => this.styleService.setCellClass(val)); break; } this.styleService.setCellClass(event.value); break; case API.setRowStyle: if (Array.isArray(event.value)) { event.value.forEach((val) => this.styleService.setRowStyle(val)); break; } this.styleService.setRowStyle(event.value); break; case API.setCellStyle: if (Array.isArray(event.value)) { event.value.forEach((val) => this.styleService.setCellStyle(val)); break; } this.styleService.setCellStyle(event.value); break; case API.setTableClass: this.tableClass = event.value; this.cdr.markForCheck(); break; case API.getPaginationTotalItems: return this.paginationComponent.paginationDirective.getTotalItems(); case API.getPaginationCurrentPage: return this.paginationComponent.paginationDirective.getCurrent(); case API.getPaginationLastPage: return this.paginationComponent.paginationDirective.getLastPage(); case API.getNumberOfRowsPerPage: return this.paginationComponent.paginationDirective.isLastPage() ? this.paginationComponent.paginationDirective.getTotalItems() % this.limit : this.limit; case API.setPaginationCurrentPage: this.paginationComponent.paginationDirective.setCurrent(event.value); break; case API.setPaginationRange: this.paginationComponent.ranges = event.value; break; case API.setPaginationPreviousLabel: this.paginationComponent.previousLabel = event.value; break; case API.setPaginationNextLabel: this.paginationComponent.nextLabel = event.value; break; case API.setPaginationDisplayLimit: this.paginationComponent.changeLimit(event.value, true); break; case API.sortBy: const column = { title: '', key: event.value.column, orderBy: event.value.order }; this.orderBy(column); this.cdr.detectChanges(); break; default: break; } } setColumnOrder(column) { const key = column.key; switch (this.sortState.get(key)) { case '': case undefined: this.sortState.set(key, column.orderBy || 'desc'); break; case 'asc': this.config.threeWaySort ? this.sortState.set(key, '') : this.sortState.set(key, 'desc'); break; case 'desc': this.sortState.set(key, 'asc'); break; } if (this.sortState.size > 1) { const temp = this.sortState.get(key); this.sortState.clear(); this.sortState.set(key, temp); } } emitEvent(event, value) { this.event.emit({ event, value }); if (this.config.persistState) { localStorage.setItem(event, JSON.stringify(value)); } if (this.config.logger) { // eslint-disable-next-line no-console console.log({ event, value }); } } dragEnter($event) { $event.preventDefault(); $event.stopPropagation(); } dragOver($event) { $event.preventDefault(); $event.stopPropagation(); } dragLeave($event) { $event.preventDefault(); $event.stopPropagation(); } drop($event) { $event.preventDefault(); $event.stopPropagation(); const file = $event.dataTransfer?.files?.[0]; if (file?.type !== 'application/json') { // eslint-disable-next-line no-console console.log('File not allowed'); return; } const fileReader = new FileReader(); fileReader.onload = (event) => { this.data = JSON.parse(event?.target?.result); this.cdr.markForCheck(); }; fileReader.readAsText(file); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: BaseComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.ScrollDispatcher }, { token: i2.StyleService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.0", type: BaseComponent, selector: "ngx-table", inputs: { configuration: "configuration", data: "data", pagination: "pagination", groupRowsBy: "groupRowsBy", id: "id", toggleRowIndex: "toggleRowIndex", detailsTemplate: "detailsTemplate", summaryTemplate: "summaryTemplate", groupRowsHeaderTemplate: "groupRowsHeaderTemplate", filtersTemplate: "filtersTemplate", selectAllTemplate: "selectAllTemplate", noResultsTemplate: "noResultsTemplate", loadingTemplate: "loadingTemplate", additionalActionsTemplate: "additionalActionsTemplate", rowContextMenu: "rowContextMenu", columns: "columns", isAllSortEnabled: "isAllSortEnabled" }, outputs: { event: "event" }, host: { listeners: { "document:click": "onContextMenuClick($event.target)" } }, providers: [DefaultConfigService, GroupRowsService, StyleService], queries: [{ propertyName: "rowTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "paginationComponent", first: true, predicate: ["paginationComponent"], descendants: true }, { propertyName: "contextMenu", first: true, predicate: ["contextMenu"], descendants: true }, { propertyName: "table", first: true, predicate: ["table"], descendants: true }, { propertyName: "viewPort", first: true, predicate: CdkVirtualScrollViewport, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\r\n class=\"ngx-container\"\r\n [class.ngx-container--dark]=\"config.tableLayout.theme === 'dark'\"\r\n (dragenter)=\"dragEnter($event)\"\r\n (dragover)=\"dragOver($event)\"\r\n (dragleave)=\"dragLeave($event)\"\r\n (drop)=\"drop($event)\"\r\n>\r\n <table\r\n [id]=\"id\"\r\n #table\r\n [ngClass]=\"tableClass === null || tableClass === '' ? 'ngx-table' : tableClass\"\r\n [class.ngx-table__table--tiny]=\"config.tableLayout.style === 'tiny'\"\r\n [class.ngx-table__table--normal]=\"config.tableLayout.style === 'normal'\"\r\n [class.ngx-table__table--big]=\"config.tableLayout.style === 'big'\"\r\n [class.ngx-table__table--borderless]=\"config.tableLayout.borderless\"\r\n [class.ngx-table__table--dark]=\"config.tableLayout.theme === 'dark'\"\r\n [class.ngx-table__table--hoverable]=\"config.tableLayout.hover\"\r\n [class.ngx-table__table--striped]=\"config.tableLayout.striped\"\r\n [class.ngx-table__horizontal-scroll]=\"config.horizontalScroll && !config.isLoading\"\r\n >\r\n <thead\r\n [class.ngx-infinite-scroll-viewport-thead]=\"config.infiniteScroll\"\r\n table-thead\r\n [config]=\"config\"\r\n [sortKey]=\"sortKey\"\r\n [sortState]=\"sortState\"\r\n [selectAllTemplate]=\"selectAllTemplate\"\r\n [filtersTemplate]=\"filtersTemplate\"\r\n [additionalActionsTemplate]=\"additionalActionsTemplate\"\r\n [columns]=\"columns\"\r\n (selectAll)=\"onSelectAll()\"\r\n (filter)=\"onSearch($event)\"\r\n (order)=\"orderBy($event)\"\r\n (event)=\"emitEvent($event.event, $event.value)\"\r\n ></thead>\r\n <tbody *ngIf=\"data && !config.isLoading && !config.rowReorder\">\r\n <ng-container *ngIf=\"rowTemplate\">\r\n <ul\r\n class=\"ngx-table__table-row-context-menu\"\r\n [ngStyle]=\"{\r\n position: 'absolute',\r\n top: rowContextMenuPosition.top,\r\n left: rowContextMenuPosition.left\r\n }\"\r\n *ngIf=\"rowContextMenuPosition.top\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowContextMenu\"\r\n [ngTemplateOutletContext]=\"{ $implicit: rowContextMenuPosition.value }\"\r\n >\r\n </ng-container>\r\n </ul>\r\n <ng-container *ngIf=\"!config.infiniteScroll\">\r\n <ng-container\r\n *ngFor=\"\r\n let row of data\r\n | sort: sortBy\r\n | search: term:filteredCountSubject\r\n | global: globalSearchTerm:filteredCountSubject\r\n | paginate: { itemsPerPage: limit, currentPage: page, totalItems: count, id: id }\r\n \"\r\n >\r\n <tr\r\n (click)=\"onClick($event, row, '', null, data.indexOf(row))\"\r\n #contextMenu\r\n (contextmenu)=\"onRowContextMenu($event, row, '', null, data.indexOf(row))\"\r\n (dblclick)=\"onDoubleClick($event, row, '', null, data.indexOf(row))\"\r\n [class.ngx-table__table-row--selected]=\"\r\n data.indexOf(row) === selectedRow && !config.selectCell\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: data.indexOf(row) }\"\r\n >\r\n </ng-container>\r\n <td *ngIf=\"config.detailsTemplate\">\r\n <span\r\n class=\"ngx-icon\"\r\n *ngIf=\"arrowDefinition\"\r\n [ngClass]=\"\r\n isRowCollapsed(data.indexOf(row))\r\n ? 'ngx-icon-arrow-down'\r\n : 'ngx-icon-arrow-right'\r\n \"\r\n (click)=\"collapseRow(data.indexOf(row))\"\r\n >\r\n </span>\r\n </td>\r\n </tr>\r\n <tr\r\n *ngIf=\"\r\n (config.detailsTemplate && selectedDetailsTemplateRowId.has(data.indexOf(row))) ||\r\n config.collapseAllRows\r\n \"\r\n >\r\n <td [attr.colspan]=\"columns.length + 1\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"detailsTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: data.indexOf(row) }\"\r\n >\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </ng-container>\r\n </ng-container>\r\n <cdk-virtual-scroll-viewport\r\n itemSize=\"50\"\r\n *ngIf=\"config.infiniteScroll\"\r\n class=\"ngx-infinite-scroll-viewport\"\r\n >\r\n <ng-container\r\n *cdkVirtualFor=\"\r\n let row of data\r\n | sort: sortBy\r\n | search: term:filteredCountSubject\r\n | global: globalSearchTerm:filteredCountSubject;\r\n let rowIndex = index\r\n \"\r\n >\r\n <tr\r\n (click)=\"onClick($event, row, '', null, rowIndex)\"\r\n #contextMenu\r\n (contextmenu)=\"onRowContextMenu($event, row, '', null, rowIndex)\"\r\n (dblclick)=\"onDoubleClick($event, row, '', null, rowIndex)\"\r\n [class.ngx-table__table-row--selected]=\"\r\n rowIndex === selectedRow && !config.selectCell\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: rowIndex }\"\r\n >\r\n </ng-container>\r\n <td *ngIf=\"config.detailsTemplate\">\r\n <span\r\n class=\"ngx-icon\"\r\n *ngIf=\"arrowDefinition\"\r\n [ngClass]=\"\r\n isRowCollapsed(rowIndex) ? 'ngx-icon-arrow-down' : 'ngx-icon-arrow-right'\r\n \"\r\n (click)=\"collapseRow(rowIndex)\"\r\n >\r\n </span>\r\n </td>\r\n </tr>\r\n <tr\r\n *ngIf=\"\r\n (config.detailsTemplate && selectedDetailsTemplateRowId.has(rowIndex)) ||\r\n config.collapseAllRows\r\n \"\r\n >\r\n <td [attr.colspan]=\"columns.length + 1\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"detailsTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: rowIndex }\"\r\n >\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </ng-container>\r\n </cdk-virtual-scroll-viewport>\r\n </ng-container>\r\n <ng-container *ngIf=\"!rowTemplate && !config.groupRows\">\r\n <ul\r\n class=\"ngx-table__table-row-context-menu\"\r\n [ngStyle]=\"{\r\n position: 'absolute',\r\n top: rowContextMenuPosition.top,\r\n left: rowContextMenuPosition.left\r\n }\"\r\n *ngIf=\"rowContextMenuPosition.top\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowContextMenu\"\r\n [ngTemplateOutletContext]=\"{ $implicit: rowContextMenuPosition.value }\"\r\n >\r\n </ng-container>\r\n </ul>\r\n <ng-container *ngIf=\"!config.infiniteScroll\">\r\n <ng-container\r\n *ngFor=\"\r\n let row of data\r\n | sort: sortBy\r\n | search: term:filteredCountSubject\r\n | global: globalSearchTerm:filteredCountSubject\r\n | paginate: { itemsPerPage: limit, currentPage: page, totalItems: count, id: id }\r\n \"\r\n >\r\n <tr\r\n [class.ngx-table__table-row--selected]=\"\r\n data.indexOf(row) === selectedRow && !config.selectCell\r\n \"\r\n >\r\n <td *ngIf=\"config.checkboxes\">\r\n <label class=\"ngx-form-checkbox\">\r\n <input\r\n type=\"checkbox\"\r\n id=\"checkbox-{{ data.indexOf(row) }}\"\r\n [checked]=\"isSelected || selectedCheckboxes.has(data.indexOf(row))\"\r\n (change)=\"onCheckboxSelect($event, row, data.indexOf(row))\"\r\n />\r\n <em class=\"ngx-form-icon\"></em>\r\n </label>\r\n </td>\r\n <td *ngIf=\"config.radio\">\r\n <label>\r\n <input\r\n type=\"radio\"\r\n id=\"radio-{{ data.indexOf(row) }}\"\r\n name=\"radio\"\r\n (change)=\"onRadioSelect($event, row, data.indexOf(row))\"\r\n />\r\n </label>\r\n </td>\r\n <ng-container *ngFor=\"let column of columns; let colIndex = index\">\r\n <td\r\n (click)=\"onClick($event, row, column.key, colIndex, data.indexOf(row))\"\r\n #contextMenu\r\n (contextmenu)=\"\r\n onRowContextMenu($event, row, column.key, colIndex, data.indexOf(row))\r\n \"\r\n (dblclick)=\"onDoubleClick($event, row, column.key, colIndex, data.indexOf(row))\"\r\n [class.pinned-left]=\"column.pinned\"\r\n [ngClass]=\"column.cssClass ? column.cssClass.name : ''\"\r\n [style.left]=\"styleService.pinnedWidth(column.pinned, colIndex)\"\r\n [class.ngx-table__table-col--selected]=\"\r\n colIndex === selectedCol && !config.selectCell\r\n \"\r\n [class.ngx-table__table-cell--selected]=\"\r\n colIndex === selectedCol &&\r\n data.indexOf(row) === selectedRow &&\r\n !config.selectCol &&\r\n !config.selectRow\r\n \"\r\n >\r\n <div *ngIf=\"!column.cellTemplate\">{{ row | render: column.key }}</div>\r\n <ng-container\r\n *ngIf=\"column.cellTemplate\"\r\n [ngTemplateOutlet]=\"column.cellTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: row,\r\n rowIndex: data.indexOf(row),\r\n column: column\r\n }\"\r\n >\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n <td *ngIf=\"config.additionalActions || config.detailsTemplate\">\r\n <span\r\n class=\"ngx-icon\"\r\n *ngIf=\"arrowDefinition\"\r\n [ngClass]=\"\r\n isRowCollapsed(data.indexOf(row))\r\n ? 'ngx-icon-arrow-down'\r\n : 'ngx-icon-arrow-right'\r\n \"\r\n (click)=\"collapseRow(data.indexOf(row))\"\r\n >\r\n </span>\r\n </td>\r\n </tr>\r\n <tr\r\n *ngIf=\"\r\n (config.detailsTemplate && selectedDetailsTemplateRowId.has(data.indexOf(row))) ||\r\n config.collapseAllRows\r\n \"\r\n >\r\n <td *ngIf=\"config.checkboxes || config.radio\"></td>\r\n <td [attr.colspan]=\"columns.length + 1\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"detailsTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: data.indexOf(row) }\"\r\n >\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </ng-container>\r\n </ng-container>\r\n <!-- infinite scroll -->\r\n <cdk-virtual-scroll-viewport\r\n itemSize=\"50\"\r\n *ngIf=\"config.infiniteScroll\"\r\n class=\"ngx-infinite-scroll-viewport\"\r\n >\r\n <ng-container\r\n *cdkVirtualFor=\"\r\n let row of data\r\n | sort: sortBy\r\n | search: term:filteredCountSubject\r\n | global: globalSearchTerm:filteredCountSubject;\r\n let rowIndex = index\r\n \"\r\n >\r\n <tr\r\n [class.ngx-table__table-row--selected]=\"\r\n rowIndex === selectedRow && !config.selectCell\r\n \"\r\n >\r\n <td *ngIf=\"config.checkboxes\" width=\"3%\">\r\n <label class=\"ngx-form-checkbox\">\r\n <input\r\n type=\"checkbox\"\r\n id=\"checkbox-infinite-scroll-{{ rowIndex }}\"\r\n [checked]=\"isSelected || selectedCheckboxes.has(rowIndex)\"\r\n (change)=\"onCheckboxSelect($event, row, rowIndex)\"\r\n />\r\n <em class=\"ngx-form-icon\"></em>\r\n </label>\r\n </td>\r\n <td *ngIf=\"config.radio\" width=\"3%\">\r\n <label>\r\n <input\r\n type=\"radio\"\r\n id=\"radio-infinite-scroll-{{ rowIndex }}\"\r\n name=\"radio\"\r\n (change)=\"onRadioSelect($event, row, rowIndex)\"\r\n />\r\n </label>\r\n </td>\r\n <ng-container *ngFor=\"let column of columns; let colIndex = index\">\r\n <td\r\n (click)=\"onClick($event, row, column.key, colIndex, rowIndex)\"\r\n #contextMenu\r\n (contextmenu)=\"onRowContextMenu($event, row, column.key, colIndex, rowIndex)\"\r\n (dblclick)=\"onDoubleClick($event, row, column.key, colIndex, rowIndex)\"\r\n [class.pinned-left]=\"column.pinned\"\r\n [ngClass]=\"column.cssClass ? column.cssClass.name : ''\"\r\n [style.left]=\"styleService.pinnedWidth(column.pinned, colIndex)\"\r\n [class.ngx-table__table-col--selected]=\"\r\n colIndex === selectedCol && !config.selectCell\r\n \"\r\n [class.ngx-table__table-cell--selected]=\"\r\n colIndex === selectedCol &&\r\n rowIndex === selectedRow &&\r\n !config.selectCol &&\r\n !config.selectRow\r\n \"\r\n >\r\n <div *ngIf=\"!column.cellTemplate\">{{ row | render: column.key }}</div>\r\n <ng-container\r\n *ngIf=\"column.cellTemplate\"\r\n [ngTemplateOutlet]=\"column.cellTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: row,\r\n rowIndex: rowIndex,\r\n column: column\r\n }\"\r\n >\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n <td *ngIf=\"config.additionalActions || config.detailsTemplate\">\r\n <span\r\n class=\"ngx-icon\"\r\n *ngIf=\"arrowDefinition\"\r\n [ngClass]=\"\r\n isRowCollapsed(rowIndex) ? 'ngx-icon-arrow-down' : 'ngx-icon-arrow-right'\r\n \"\r\n (click)=\"collapseRow(rowIndex)\"\r\n >\r\n </span>\r\n </td>\r\n </tr>\r\n <tr\r\n *ngIf=\"\r\n (config.detailsTemplate && selectedDetailsTemplateRowId.has(rowIndex)) ||\r\n config.collapseAllRows\r\n \"\r\n >\r\n <td *ngIf=\"config.checkboxes || config.radio\"></td>\r\n <td [attr.colspan]=\"columns.length + 1\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"detailsTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: rowIndex }\"\r\n >\r\n </ng-container>\r\n </td>\r\n </tr>\r\n </ng-container>\r\n </cdk-virtual-scroll-viewport>\r\n </ng-container>\r\n <ng-container *ngIf=\"!rowTemplate && config.groupRows\">\r\n <ng-container\r\n *ngFor=\"\r\n let group of grouped\r\n | sort: sortBy:config\r\n | search: term:filteredCountSubject:config\r\n | global: globalSearchTerm:filteredCountSubject\r\n | paginate: { itemsPerPage: limit, currentPage: page, totalItems: count, id: id };\r\n let rowIndex = index\r\n \"\r\n >\r\n <tr>\r\n <ng-container *ngIf=\"!groupRowsHeaderTemplate\">\r\n <td [attr.colspan]=\"columns.length\">\r\n <div>{{ group[0][groupRowsBy] }} ({{ group.length }})</div>\r\n </td>\r\n </ng-container>\r\n <ng-container\r\n *ngIf=\"groupRowsHeaderTemplate\"\r\n [ngTemplateOutlet]=\"groupRowsHeaderTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n total: group.length,\r\n key: groupRowsBy,\r\n value: group[0] ? group[0][groupRowsBy] : '',\r\n group: group,\r\n index: rowIndex\r\n }\"\r\n >\r\n </ng-container>\r\n <td>\r\n <span\r\n class=\"ngx-icon\"\r\n *ngIf=\"arrowDefinition\"\r\n [ngClass]=\"\r\n isRowCollapsed(rowIndex) ? 'ngx-icon-arrow-down' : 'ngx-icon-arrow-right'\r\n \"\r\n (click)=\"collapseRow(rowIndex)\"\r\n >\r\n </span>\r\n </td>\r\n </tr>\r\n <ng-container *ngIf=\"selectedDetailsTemplateRowId.has(rowIndex)\">\r\n <tr *ngFor=\"let row of group\">\r\n <td *ngFor=\"let column of columns\">\r\n {{ row | render: column.key }}\r\n <!-- TODO allow users to add groupRowsTemplateRef -->\r\n </td>\r\n <td></td>\r\n </tr>\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </tbody>\r\n <tbody\r\n *ngIf=\"data && !config.isLoading && config.rowReorder\"\r\n class=\"ngx-draggable-row-area\"\r\n cdkDropList\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n >\r\n <ng-container *ngIf=\"!rowTemplate && !config.groupRows\">\r\n <ng-container\r\n *ngFor=\"\r\n let row of data\r\n | sort: sortBy\r\n | search: term:filteredCountSubject\r\n | global: globalSearchTerm:filteredCountSubject\r\n | paginate: { itemsPerPage: limit, currentPage: page, totalItems: count, id: id }\r\n \"\r\n >\r\n <tr\r\n class=\"ngx-draggable-row\"\r\n cdkDrag\r\n (cdkDragStarted)=\"onDragStart($event)\"\r\n [cdkDragStartDelay]=\"config.reorderDelay || 0\"\r\n cdkDragLockAxis=\"y\"\r\n >\r\n <td *ngIf=\"config.checkboxes\">\r\n <label class=\"ngx-form-checkbox\">\r\n <input\r\n type=\"checkbox\"\r\n id=\"checkbox-draggable-{{ data.indexOf(row) }}\"\r\n [checked]=\"isSelected || selectedCheckboxes.has(data.indexOf(row))\"\r\n (change)=\"onCheckboxSelect($event, row, data.indexOf(row))\"\r\n />\r\n <em class=\"ngx-form-icon\"></em>\r\n </label>\r\n </td>\r\n <td *ngIf=\"config.radio\">\r\n <label>\r\n <input\r\n type=\"radio\"\r\n id=\"radio-draggable-{{ data.indexOf(row) }}\"\r\n name=\"radio\"\r\n (change)=\"onRadioSelect($event, row, data.indexOf(row))\"\r\n />\r\n </label>\r\n </td>\r\n <ng-container *ngFor=\"let column of columns; let colIndex = index\">\r\n <td\r\n (click)=\"onClick($event, row, column.key, colIndex, data.indexOf(row))\"\r\n (dblclick)=\"onDoubleClick($event, row, column.key, colIndex, data.indexOf(row))\"\r\n [class.ngx-table__table-col--selected]=\"\r\n colIndex === selectedCol && !config.selectCell\r\n \"\r\n [class.ngx-table__table-cell--selected]=\"\r\n colIndex === selectedCol &&\r\n data.indexOf(row) === selectedRow &&\r\n !config.selectCol &&\r\n !config.selectRow\r\n \"\r\n >\r\n <div *ngIf=\"!column.cellTemplate\">{{ row | render: column.key }}</div>\r\n <ng-container\r\n *ngIf=\"column.cellTemplate\"\r\n [ngTemplateOutlet]=\"column.cellTemplate\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: row,\r\n rowIndex: data.indexOf(row),\r\n column: column\r\n }\"\r\n >\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n </tr>\r\n </ng-container>\r\n </ng-container>\r\n </tbody>\r\n <tbody *ngIf=\"filterCount === 0\">\r\n <tr class=\"ngx-table__body-empty\">\r\n <ng-container *ngIf=\"noResultsTemplate\" [ngTemplateOutlet]=\"noResultsTemplate\">\r\n </ng-container>\r\n <td [attr.colspan]=\"columns && columns.length + 1\" *ngIf=\"!noResultsTemplate\">\r\n <div class=\"ngx-table__table-no-results\">No results</div>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tbody *ngIf=\"config.isLoading\">\r\n <tr class=\"ngx-table__body-loading\">\r\n <ng-container *ngIf=\"loadingTemplate\" [ngTemplateOutlet]=\"loadingTemplate\"> </ng-container>\r\n <td [attr.colspan]=\"columns && columns.length + 1\" *ngIf=\"!loadingTemplate\">\r\n <div [style.height.px]=\"loadingHeight\" class=\"ngx-table__table-loader-wrapper\">\r\n <div class=\"ngx-table__table-loader\"></div>\r\n </div>\r\n </td>\r\n </tr>\r\n </tbody>\r\n <tfoot *ngIf=\"summaryTemplate\">\r\n <tr>\r\n <ng-container\r\n [ngTemplateOutlet]=\"summaryTemplate\"\r\n [ngTemplateOutletContext]=\"{ total: data.length, limit: limit, page: page }\"\r\n >\r\n </ng-container>\r\n </tr>\r\n </tfoot>\r\n </table>\r\n <pagination\r\n [attr.id]=\"'pagination' + id\"\r\n [id]=\"id\"\r\n #paginationComponent\r\n [config]=\"config\"\r\n [pagination]=\"pagination\"\r\n (updateRange)=\"onPagination($event)\"\r\n >\r\n </pagination>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i4.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i4.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: i5.PaginationComponent, selector: "pagination", inputs: ["pagination", "config", "id"], outputs: ["updateRange"] }, { kind: "component", type: i6.TableTHeadComponent, selector: "[table-thead]", inputs: ["config", "columns", "sortKey", "sortState", "selectAllTemplate", "filtersTemplate", "additionalActionsTemplate", "isAllSortEnabled"], outputs: ["filter", "order", "selectAll", "event"] }, { kind: "pipe", type: i7.PaginatePipe, name: "paginate" }, { kind: "pipe", type: i8.SearchPipe, name: "search" }, { kind: "pipe", type: i9.RenderPipe, name: "render" }, { kind: "pipe", type: i10.GlobalSearchPipe, name: "global" }, { kind: "pipe", type: i11.SortPipe, name: "sort" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: BaseComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-table', providers: [DefaultConfigService, GroupRowsService, StyleService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"ngx-container\"\r\n [class.ngx-container--dark]=\"config.tableLayout.theme === 'dark'\"\r\n (dragenter)=\"dragEnter($event)\"\r\n (dragover)=\"dragOver($event)\"\r\n (dragleave)=\"dragLeave($event)\"\r\n (drop)=\"drop($event)\"\r\n>\r\n <table\r\n [id]=\"id\"\r\n #table\r\n [ngClass]=\"tableClass === null || tableClass === '' ? 'ngx-table' : tableClass\"\r\n [class.ngx-table__table--tiny]=\"config.tableLayout.style === 'tiny'\"\r\n [class.ngx-table__table--normal]=\"config.tableLayout.style === 'normal'\"\r\n [class.ngx-table__table--big]=\"config.tableLayout.style === 'big'\"\r\n [class.ngx-table__table--borderless]=\"config.tableLayout.borderless\"\r\n [class.ngx-table__table--dark]=\"config.tableLayout.theme === 'dark'\"\r\n [class.ngx-table__table--hoverable]=\"config.tableLayout.hover\"\r\n [class.ngx-table__table--striped]=\"config.tableLayout.striped\"\r\n [class.ngx-table__horizontal-scroll]=\"config.horizontalScroll && !config.isLoading\"\r\n >\r\n <thead\r\n [class.ngx-infinite-scroll-viewport-thead]=\"config.infiniteScroll\"\r\n table-thead\r\n [config]=\"config\"\r\n [sortKey]=\"sortKey\"\r\n [sortState]=\"sortState\"\r\n [selectAllTemplate]=\"selectAllTemplate\"\r\n [filtersTemplate]=\"filtersTemplate\"\r\n [additionalActionsTemplate]=\"additionalActionsTemplate\"\r\n [columns]=\"columns\"\r\n (selectAll)=\"onSelectAll()\"\r\n (filter)=\"onSearch($event)\"\r\n (order)=\"orderBy($event)\"\r\n (event)=\"emitEvent($event.event, $event.value)\"\r\n ></thead>\r\n <tbody *ngIf=\"data && !config.isLoading && !config.rowReorder\">\r\n <ng-container *ngIf=\"rowTemplate\">\r\n <ul\r\n class=\"ngx-table__table-row-context-menu\"\r\n [ngStyle]=\"{\r\n position: 'absolute',\r\n top: rowContextMenuPosition.top,\r\n left: rowContextMenuPosition.left\r\n }\"\r\n *ngIf=\"rowContextMenuPosition.top\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowContextMenu\"\r\n [ngTemplateOutletContext]=\"{ $implicit: rowContextMenuPosition.value }\"\r\n >\r\n </ng-container>\r\n </ul>\r\n <ng-container *ngIf=\"!config.infiniteScroll\">\r\n <ng-container\r\n *ngFor=\"\r\n let row of data\r\n | sort: sortBy\r\n | search: term:filteredCountSubject\r\n | global: globalSearchTerm:filteredCountSubject\r\n | paginate: { itemsPerPage: limit, currentPage: page, totalItems: count, id: id }\r\n \"\r\n >\r\n <tr\r\n (click)=\"onClick($event, row, '', null, data.indexOf(row))\"\r\n #contextMenu\r\n (contextmenu)=\"onRowContextMenu($event, row, '', null, data.indexOf(row))\"\r\n (dblclick)=\"onDoubleClick($event, row, '', null, data.indexOf(row))\"\r\n [class.ngx-table__table-row--selected]=\"\r\n data.indexOf(row) === selectedRow && !config.selectCell\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"rowTemplate\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, index: data.indexOf(row) }\"\r\n >\r\n </ng-container>\r\n <td *ngIf=\"config.detailsTemplate\">\r\n <span\r\n class=\"ngx-icon\"\r\n *ngIf=\"arrowDefinition\"\r\n [ngClass]=\"\r\n isRowCollapsed(data.indexOf(row))\r\n ? 'ngx-icon-arrow-down'\r\n : 'ngx-icon-arrow-right'\r\n \"\r\n (click)=\"collapseRow(data.indexOf(row))\"\r\n >\r\n </span>\r\n </td>\r\n </tr>\r\n <tr\r\n *ngIf=\"\r\n (config.detailsTemplate && selectedDetailsTemplateRowId.has(data.indexOf(row))) ||\r\n config.collapseAllRows\r\n \"\r\n >\r\n <td [attr.colspan]=\"