import { Directive, Injector, OnDestroy } from '@angular/core'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { distinctUntilChanged, map, switchMap } from 'rxjs/operators'; import { FilterService } from '../filtering'; import { SortingService } from '../sorting'; import { AutoUnsubscribe } from '../utils'; import { SearchService } from '../search'; import { EntitiesService } from './services'; import { IListable, TableColumnConfig } from './models'; export const DefaultListingServices = [FilterService, SearchService, EntitiesService, SortingService] as const; @Directive() export abstract class ListingComponent extends AutoUnsubscribe implements OnDestroy { readonly filterService = this._injector.get(FilterService); readonly searchService = this._injector.get>(SearchService); readonly sortingService = this._injector.get>(SortingService); readonly entitiesService = this._injector.get>(EntitiesService); readonly noMatch$ = this._noMatch$; readonly noContent$ = this._noContent$; readonly sortedDisplayedEntities$ = this._sortedDisplayedEntities$; readonly listingMode$: Observable; /** * @deprecated Use routerLink getter from IListable */ readonly routerLinkFn?: (entity: T) => string | string[]; abstract readonly tableColumnConfigs: readonly TableColumnConfig[]; abstract readonly tableHeaderLabel: string; private readonly _listingMode$ = new BehaviorSubject(ListingModes.table); protected constructor(protected readonly _injector: Injector) { super(); this.listingMode$ = this._listingMode$.asObservable(); } get allEntities(): T[] { return this.entitiesService.all; } set listingMode(listingMode: ListingMode) { this._listingMode$.next(listingMode); } private get _sortedDisplayedEntities$(): Observable { const sort = (entities: T[]) => this.sortingService.defaultSort(entities); const sortedEntities = () => this.entitiesService.displayed$.pipe(map(sort)); return this.sortingService.sortingOption$.pipe(switchMap(sortedEntities)); } private get _noMatch$(): Observable { return combineLatest([this.entitiesService.allLength$, this.entitiesService.displayedLength$]).pipe( map(([hasEntities, hasDisplayedEntities]) => !!hasEntities && !hasDisplayedEntities), distinctUntilChanged() ); } private get _noContent$(): Observable { return combineLatest([this._noMatch$, this.entitiesService.noData$]).pipe( map(([noMatch, noData]) => noMatch || noData), distinctUntilChanged() ); } toggleEntitySelected(event: MouseEvent, entity: T): void { event.stopPropagation(); this.entitiesService.select(entity); } isSelected(entity: T): boolean { return this.entitiesService.isSelected(entity); } }