From fc69faac3a4d271e2c2c8a978995d70770b5effc Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Sat, 7 Aug 2021 16:53:52 +0300 Subject: [PATCH] add entities service --- src/index.ts | 1 + src/lib/tables/entities.service.ts | 108 +++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/lib/tables/entities.service.ts diff --git a/src/index.ts b/src/index.ts index 28de618..b76661d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,5 +19,6 @@ export * from './lib/sorting/sorting.service'; export * from './lib/sorting/models/sorting-option.model'; export * from './lib/sorting/models/sorting-order.type'; export * from './lib/search/search.service'; +export * from './lib/tables/entities.service'; export * from './lib/tables/models/table-column-config.model'; export * from './lib/tables/table-column-name/table-column-name.component'; diff --git a/src/lib/tables/entities.service.ts b/src/lib/tables/entities.service.ts new file mode 100644 index 0000000..63ce0a9 --- /dev/null +++ b/src/lib/tables/entities.service.ts @@ -0,0 +1,108 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, combineLatest, Observable, pipe } from 'rxjs'; +import { distinctUntilChanged, map, tap } from 'rxjs/operators'; +import { FilterService, getFilteredEntities, SearchService } from '@iqser/common-ui'; + +const toLengthValue = (entities: unknown[]) => entities?.length ?? 0; +const getLength = pipe(map(toLengthValue), distinctUntilChanged()); + +@Injectable() +export class EntitiesService { + private readonly _all$ = new BehaviorSubject([]); + readonly all$ = this._all$.asObservable(); + readonly allLength$ = this._all$.pipe(getLength); + + private _displayed: T[] = []; + readonly displayed$ = this._getDisplayed$; + readonly displayedLength$ = this.displayed$.pipe(getLength); + + private readonly _selected$ = new BehaviorSubject([]); + readonly selected$ = this._selected$.asObservable(); + readonly selectedLength$ = this._selected$.pipe(getLength); + + readonly noData$ = this._noData$; + readonly areAllSelected$ = this._areAllSelected$; + readonly areSomeSelected$ = this._areSomeSelected$; + readonly notAllSelected$ = this._notAllSelected$; + + constructor(private readonly _filterService: FilterService, private readonly _searchService: SearchService) {} + + get all(): T[] { + return Object.values(this._all$.getValue()); + } + + get selected(): T[] { + return Object.values(this._selected$.getValue()); + } + + private get _getDisplayed$(): Observable { + const filterGroups$ = this._filterService.filterGroups$; + const searchValue$ = this._searchService.valueChanges$; + + return combineLatest([this.all$, filterGroups$, searchValue$]).pipe( + map(([entities, filterGroups]) => getFilteredEntities(entities, filterGroups)), + map(entities => this._searchService.searchIn(entities)), + tap(displayed => (this._displayed = displayed)) + ); + } + + private get _areAllSelected$(): Observable { + return combineLatest([this.displayedLength$, this.selectedLength$]).pipe( + map(([displayedLength, selectedLength]) => !!displayedLength && displayedLength === selectedLength), + distinctUntilChanged() + ); + } + + private get _areSomeSelected$(): Observable { + return this.selectedLength$.pipe( + map(length => !!length), + distinctUntilChanged() + ); + } + + private get _notAllSelected$(): Observable { + return combineLatest([this.areAllSelected$, this.areSomeSelected$]).pipe( + map(([allAreSelected, someAreSelected]) => !allAreSelected && someAreSelected), + distinctUntilChanged() + ); + } + + private get _noData$(): Observable { + return this.allLength$.pipe( + map(length => length === 0), + distinctUntilChanged() + ); + } + + private get _allSelected() { + return this._displayed.length !== 0 && this._displayed.length === this.selected.length; + } + + setEntities(newEntities: T[]): void { + this._all$.next(newEntities); + } + + setSelected(newEntities: T[]): void { + this._selected$.next(newEntities); + } + + isSelected(entity: T): boolean { + return this.selected.indexOf(entity) !== -1; + } + + selectAll(): void { + if (this._allSelected) return this.setSelected([]); + this.setSelected(this._displayed); + } + + select(entity: T): void { + const currentEntityIdx = this.selected.indexOf(entity); + if (currentEntityIdx === -1) return this.setSelected([...this.selected, entity]); + this.setSelected(this.selected.filter((el, idx) => idx !== currentEntityIdx)); + } + + updateSelection(): void { + const items = this._displayed.filter(item => this.selected.includes(item)); + this.setSelected(items); + } +}