107 lines
3.9 KiB
TypeScript
107 lines
3.9 KiB
TypeScript
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<Class extends IListable<PrimaryKey>, PrimaryKey extends Id = Class['id']> implements OnChanges {
|
|
@ViewChild(TableContentComponent, { static: true }) private readonly _tableContent!: TableContentComponent<Class>;
|
|
readonly listingModes = ListingModes;
|
|
@Input() tableColumnConfigs!: readonly TableColumnConfig<Class>[];
|
|
@Input() bulkActions?: TemplateRef<unknown>;
|
|
@Input() headerTemplate?: TemplateRef<unknown>;
|
|
@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<string, (e: Class) => boolean>;
|
|
@Input() rowIdPrefix: string = 'item';
|
|
@Input() namePropertyKey?: string;
|
|
@Input() itemMouseEnterFn?: (entity: Class) => void;
|
|
@Input() itemMouseLeaveFn?: (entity: Class) => void;
|
|
@Output() readonly noDataAction = new EventEmitter<void>();
|
|
|
|
constructor(
|
|
@Inject(forwardRef(() => ListingComponent)) readonly listingComponent: ListingComponent<Class>,
|
|
private readonly _hostRef: ViewContainerRef,
|
|
private readonly _changeRef: ChangeDetectorRef,
|
|
readonly entitiesService: EntitiesService<Class, Class>,
|
|
) {}
|
|
|
|
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`);
|
|
}
|
|
}
|