import { AsyncPipe, NgTemplateOutlet } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, forwardRef, Inject, Input, OnChanges, Output, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, } from '@angular/core'; import { EmptyStateComponent } from '../../empty-state'; import { ListingComponent } from '../listing-component.directive'; import { Id, IListable, ListingModes, TableColumnConfig } from '../models'; import { ScrollButtonComponent } from '../scroll-button/scroll-button.component'; import { EntitiesService } from '../services'; import { TableContentComponent } from '../table-content/table-content.component'; import { TableHeaderComponent } from '../table-header/table-header.component'; const SCROLLBAR_WIDTH = 11; @Component({ selector: 'iqser-table [tableColumnConfigs] [itemSize]', templateUrl: './table.component.html', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [TableHeaderComponent, NgTemplateOutlet, AsyncPipe, EmptyStateComponent, ScrollButtonComponent, TableContentComponent], }) export class TableComponent, PrimaryKey extends Id = Class['id']> implements OnChanges { @ViewChild(TableContentComponent, { static: true }) private readonly _tableContent!: TableContentComponent; readonly listingModes = ListingModes; @Input() tableColumnConfigs!: readonly TableColumnConfig[]; @Input() bulkActions?: TemplateRef; @Input() headerTemplate?: TemplateRef; @Input() itemSize!: number; @Input() selectionEnabled = false; @Input() hasScrollButton = false; @Input() emptyColumnWidth?: string; @Input() totalSize?: number; @Input() classes?: string; @Input() noDataText?: string; @Input() noDataIcon?: string; @Input() noDataButtonIcon?: string; @Input() noDataButtonLabel?: string; @Input() showNoDataButton = false; @Input() noMatchText?: string; @Input() helpModeKey?: string; @Input() headerHelpModeKey?: string; @Input() tableItemClasses?: Record boolean>; @Input() rowIdPrefix: string = 'item'; @Input() namePropertyKey?: string; @Input() itemMouseEnterFn?: (entity: Class) => void; @Input() itemMouseLeaveFn?: (entity: Class) => void; @Output() readonly noDataAction = new EventEmitter(); constructor( @Inject(forwardRef(() => ListingComponent)) readonly listingComponent: ListingComponent, private readonly _hostRef: ViewContainerRef, private readonly _changeRef: ChangeDetectorRef, readonly entitiesService: EntitiesService, ) {} get tableHeaderLabel(): string | undefined { return this.listingComponent.tableHeaderLabel; } ngOnChanges(changes: SimpleChanges): void { if (changes['tableColumnConfigs']) { this._setStyles(); } } scrollToLastIndex(): void { this._tableContent.scrollToLastIndex(); } private _setStyles(): void { const element = this._hostRef.element.nativeElement as HTMLElement; this._setColumnsWidth(element); this._setItemSize(element); this._changeRef.markForCheck(); } private _setColumnsWidth(element: HTMLElement) { let gridTemplateColumns = ''; if (this.selectionEnabled) { gridTemplateColumns += '30px '; } for (const config of this.tableColumnConfigs) { gridTemplateColumns += `${config.width || '1fr'} `; } gridTemplateColumns += this.emptyColumnWidth || ''; gridTemplateColumns = `${gridTemplateColumns} ${SCROLLBAR_WIDTH}px`; element.style.setProperty('--gridTemplateColumns', gridTemplateColumns); } private _setItemSize(element: HTMLElement) { element.style.setProperty('--itemSize', `${this.itemSize}px`); } }