import { Component, OnInit, Input, EventEmitter, Output, OnChanges, ViewChildren, QueryList, ViewChild, AfterViewInit } from '@angular/core'; import { MatTableColumn, MatTableColumnTypes } from './MatTableColumn'; import {MatTableDataSource} from '@angular/material/table'; import { MatTableRow } from './MatTableRow'; import { MiscHelpersService } from './Services/misc-helpers.service'; import { RowActionsComponent } from './Components/RowActions/row-actions.component'; import {MatPaginator } from '@angular/material/paginator'; @Component({ selector: 'lib-MaterialTable', templateUrl: './material-table.component.html', styleUrls: ['./material-table.component.scss'], }) export class MaterialTableComponent implements OnInit, OnChanges, AfterViewInit { @ViewChildren(RowActionsComponent) rowActions!: QueryList; @ViewChild(MatPaginator) paginator!: MatPaginator; @Input() columns: MatTableColumn[] = []; @Input() results: MatTableRow[] = []; @Input() resultsTotal = 20; @Input() pagesize = 5; @Input() pageSizeOptions= [5, 10, 20] @Input() showFilter = true; @Input() showRefresh = true; @Input() showLoadMore = true; @Input() showCsv = false; @Input() loading = false; @Input() loadingCsv = false; @Input() hideActions = false; // tslint:disable-next-line: no-output-rename @Output() load = new EventEmitter<{ more: boolean; take: number }>(); // tslint:disable-next-line: no-output-rename @Output() downloadCsv = new EventEmitter(); @Output() actionClick = new EventEmitter<{ actionName: string; result: any; }>(); rows: MatTableRow[] = []; datasource: MatTableDataSource = new MatTableDataSource(); textFilter = ''; actionsWidth = 1; MatTableColumnTypes = MatTableColumnTypes; displayColumns: string[] = []; constructor(private miscHelpersService: MiscHelpersService) { } ngAfterViewInit(): void { this.datasource.paginator = this.paginator; } ngOnInit() { this.rows = this.results; this.loading = false; this.displayColumns = this.columns.map((column: MatTableColumn) => column.name); this.datasource = new MatTableDataSource(this.rows); } trackArrayById(index: number, x: any): any { return x.id; } ngOnChanges() { this.results = this.results.map((r) => { r.filterText = this.createFilterText(r); return r; }); this.updateFilter(); if (this.rowActions) { // Race condition with view children rendering setTimeout(() => { this.rowActions.forEach((r) => { r.determineElementVisibility(); }); }, 0); } } createFilterText(result: any): string { const columnsToText = this.columns.map((c) => { switch (c.type) { case MatTableColumnTypes.STRING: return result[c.prop] || ''; case MatTableColumnTypes.NUMBER: return this.miscHelpersService.formatNumber(result[c.prop]); case MatTableColumnTypes.DOLLAR: return this.miscHelpersService.formatUSD(result[c.prop]); case MatTableColumnTypes.DATE: case MatTableColumnTypes.DATETIMEDATEONLY: return this.miscHelpersService.formatMediumDate(result[c.prop]); case MatTableColumnTypes.DATETIME: return this.miscHelpersService.formatShortDateTime(result[c.prop]); case MatTableColumnTypes.YESNO: return result[c.prop] ? 'yes' : 'no'; default: return result[c.prop] || ''; } }); return this.miscHelpersService.createSearchText(...columnsToText); } refresh(): void { this.load.emit({ more: false, take: 100 }); } _downloadCsv(): void { this.downloadCsv.emit(); } _load({ more = false, take = 100, }: { more?: boolean; take?: number } = {}): void { this.load.emit({ more, take }); } updateFilter(): void { if (this.textFilter != '') { this.datasource.filter = this.textFilter.trim().toLowerCase(); } else { this.datasource.filter = ''; } } }