Move sortedDisplayedEntities from ListingComponent to ListingService
This commit is contained in:
parent
40517f145e
commit
610a88570b
@ -3,8 +3,7 @@ import { INestedFilter } from './models/nested-filter.model';
|
||||
import { IFilterGroup } from './models/filter-group.model';
|
||||
import { IFilter } from './models/filter.model';
|
||||
import { NestedFilter } from './models/nested-filter';
|
||||
import { IListable } from '../listing';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
import { Id, IListable } from '../listing';
|
||||
|
||||
function copySettings(oldFilters: INestedFilter[], newFilters: INestedFilter[]) {
|
||||
if (!oldFilters || !newFilters) {
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import { Directive, inject, OnDestroy, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { FilterService } from '../filtering';
|
||||
import { SortingService } from '../sorting';
|
||||
import { AutoUnsubscribe, shareDistinctLast } from '../utils';
|
||||
import { SearchService } from '../search';
|
||||
import { EntitiesService, ListingService } from './services';
|
||||
import { IListable, TableColumnConfig } from './models';
|
||||
import { Id } from './models/trackable';
|
||||
import { Id, IListable, TableColumnConfig } from './models';
|
||||
|
||||
@Directive()
|
||||
export abstract class ListingComponent<Class extends IListable<PrimaryKey>, PrimaryKey extends Id = Class['id']>
|
||||
@ -24,26 +23,14 @@ export abstract class ListingComponent<Class extends IListable<PrimaryKey>, Prim
|
||||
readonly noMatch$ = this.#noMatch$;
|
||||
// TODO: Move to table content component
|
||||
readonly noContent$ = this.#noContent$;
|
||||
readonly sortedDisplayedEntities$ = this.#sortedDisplayedEntities$;
|
||||
|
||||
abstract readonly tableColumnConfigs: readonly TableColumnConfig<Class>[];
|
||||
abstract readonly tableHeaderLabel: string;
|
||||
|
||||
@ViewChild('tableItemTemplate') readonly tableItemTemplate?: TemplateRef<unknown>;
|
||||
|
||||
get allEntities(): Class[] {
|
||||
return this.entitiesService.all;
|
||||
}
|
||||
|
||||
get #sortedDisplayedEntities$(): Observable<Class[]> {
|
||||
const sort = (entities: Class[]) => this.sortingService.defaultSort(entities);
|
||||
const sortedEntities$ = this.listingService.displayed$.pipe(map(sort));
|
||||
return this.sortingService.sortingOption$.pipe(
|
||||
switchMap(() => sortedEntities$),
|
||||
shareDistinctLast(),
|
||||
);
|
||||
}
|
||||
|
||||
get #noMatch$(): Observable<boolean> {
|
||||
return combineLatest([this.entitiesService.allLength$, this.listingService.displayedLength$]).pipe(
|
||||
map(([hasEntities, hasDisplayedEntities]) => !!hasEntities && !hasDisplayedEntities),
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { filter, map, startWith, tap } from 'rxjs/operators';
|
||||
import { IListable } from '../models';
|
||||
import { Id, IListable } from '../models';
|
||||
import { GenericService, QueryParam } from '../../services';
|
||||
import { getLength, List, mapEach, shareDistinctLast, shareLast } from '../../utils';
|
||||
import { Id } from '../models/trackable';
|
||||
|
||||
@Injectable()
|
||||
/**
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { map, switchMap, tap } from 'rxjs/operators';
|
||||
import { FilterService, getFilteredEntities } from '../../filtering';
|
||||
import { SearchService } from '../../search';
|
||||
import { IListable } from '../models';
|
||||
import { Id, IListable } from '../models';
|
||||
import { EntitiesService } from './entities.service';
|
||||
import { any, getLength, shareDistinctLast, shareLast } from '../../utils';
|
||||
import { Id } from '../models/trackable';
|
||||
import { SortingService } from '../../sorting';
|
||||
|
||||
@Injectable()
|
||||
export class ListingService<Class extends IListable<PrimaryKey>, PrimaryKey extends Id = Class['id']> {
|
||||
@ -18,13 +18,16 @@ export class ListingService<Class extends IListable<PrimaryKey>, PrimaryKey exte
|
||||
readonly selected$: Observable<PrimaryKey[]>;
|
||||
readonly selectedEntities$: Observable<Class[]>;
|
||||
readonly selectedLength$: Observable<number>;
|
||||
readonly sortedDisplayedEntities$: Observable<Class[]>;
|
||||
private _displayed: Class[] = [];
|
||||
private readonly _selected$ = new BehaviorSubject<PrimaryKey[]>([]);
|
||||
readonly #sortedDisplayedEntities$ = new BehaviorSubject<Class[]>([]);
|
||||
|
||||
constructor(
|
||||
protected readonly _filterService: FilterService,
|
||||
protected readonly _searchService: SearchService<Class>,
|
||||
protected readonly _entitiesService: EntitiesService<Class, Class>,
|
||||
protected readonly _sortingService: SortingService<Class>,
|
||||
) {
|
||||
this.displayed$ = this._getDisplayed$;
|
||||
this.displayedLength$ = this.displayed$.pipe(getLength, shareDistinctLast());
|
||||
@ -39,6 +42,8 @@ export class ListingService<Class extends IListable<PrimaryKey>, PrimaryKey exte
|
||||
this.areAllSelected$ = this._areAllSelected$;
|
||||
this.areSomeSelected$ = this._areSomeSelected$;
|
||||
this.notAllSelected$ = this._notAllSelected$;
|
||||
|
||||
this.sortedDisplayedEntities$ = this.#getSortedDisplayedEntities$();
|
||||
}
|
||||
|
||||
get selected(): Class[] {
|
||||
@ -113,12 +118,17 @@ export class ListingService<Class extends IListable<PrimaryKey>, PrimaryKey exte
|
||||
this.setSelected(this._displayed);
|
||||
}
|
||||
|
||||
select(entity: Class): void {
|
||||
const currentEntityIdx = this.selected.indexOf(entity);
|
||||
select(entity: Class, withShift = false): void {
|
||||
const currentlySelected = this.selected;
|
||||
const currentEntityIdx = currentlySelected.indexOf(entity);
|
||||
|
||||
if (currentEntityIdx === -1) {
|
||||
return this.setSelected([...this.selected, entity]);
|
||||
// Entity is not previously selected, select it
|
||||
this.setSelected([...currentlySelected, entity]);
|
||||
} else {
|
||||
// Entity is previously selected, deselect it
|
||||
this.setSelected(currentlySelected.slice(0, currentEntityIdx).concat(currentlySelected.slice(currentEntityIdx + 1)));
|
||||
}
|
||||
this.setSelected(this.selected.filter((_el, idx) => idx !== currentEntityIdx));
|
||||
}
|
||||
|
||||
deselect(entities: Class | Class[]) {
|
||||
@ -131,4 +141,16 @@ export class ListingService<Class extends IListable<PrimaryKey>, PrimaryKey exte
|
||||
const items = this._displayed.filter(item => this.selected.includes(item));
|
||||
this.setSelected(items);
|
||||
}
|
||||
|
||||
#getSortedDisplayedEntities$(): Observable<Class[]> {
|
||||
const sort = (entities: Class[]) => this._sortingService.defaultSort(entities);
|
||||
const sortedEntities$ = this.displayed$.pipe(map(sort));
|
||||
return this._sortingService.sortingOption$.pipe(
|
||||
switchMap(() => sortedEntities$),
|
||||
tap(sortedEntities => {
|
||||
this.#sortedDisplayedEntities$.next(sortedEntities);
|
||||
}),
|
||||
shareDistinctLast(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, Optional } from '@angular/core';
|
||||
import { SortingOrders, SortingService } from '../../sorting';
|
||||
import { KeysOf, Required } from '../../utils';
|
||||
import { IListable } from '../models';
|
||||
import { Id } from '../models/trackable';
|
||||
import { Id, IListable } from '../models';
|
||||
|
||||
const ifHasRightIcon = <T extends IListable>(thisArg: TableColumnNameComponent<T>) => !!thisArg.rightIcon;
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
id="virtual-scroll"
|
||||
iqserHasScrollbar
|
||||
>
|
||||
<ng-container *cdkVirtualFor="let entity of listingComponent.sortedDisplayedEntities$ | async; trackBy: trackBy">
|
||||
<ng-container *cdkVirtualFor="let entity of listingService.sortedDisplayedEntities$ | async; trackBy: trackBy">
|
||||
<!-- mouseenter and mouseleave triggers change detection event if itemMouse functions are undefined -->
|
||||
<!-- this little hack below ensures that change detection won't be triggered if functions are undefined -->
|
||||
<div
|
||||
|
||||
@ -3,12 +3,11 @@ import { AfterViewInit, Component, forwardRef, HostListener, Inject, Input, OnDe
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { delay, tap } from 'rxjs/operators';
|
||||
import { AutoUnsubscribe, trackByFactory } from '../../utils';
|
||||
import { IListable } from '../models';
|
||||
import { Id, IListable } from '../models';
|
||||
import { ListingComponent, ListingService } from '../index';
|
||||
import { HasScrollbarDirective } from '../../scrollbar';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { HelpModeService } from '../../help-mode';
|
||||
import { Id } from '../models/trackable';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-table-content',
|
||||
|
||||
@ -29,8 +29,8 @@ export class TableItemComponent<T extends IListable> implements OnChanges {
|
||||
this.#entityChanged$.next(this.entity);
|
||||
}
|
||||
|
||||
toggleEntitySelected(event: MouseEvent, entity: T): void {
|
||||
event.stopPropagation();
|
||||
this.listingService.select(entity);
|
||||
toggleEntitySelected($event: MouseEvent, entity: T): void {
|
||||
$event.stopPropagation();
|
||||
this.listingService.select(entity, $event.shiftKey);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, TemplateRef } from '@angular/core';
|
||||
import { FilterService } from '../../filtering';
|
||||
import { EntitiesService, ListingService } from '../services';
|
||||
import { IListable, ListingMode, ListingModes, TableColumnConfig } from '../models';
|
||||
import { Id } from '../models/trackable';
|
||||
import { Id, IListable, ListingMode, ListingModes, TableColumnConfig } from '../models';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-table-header [tableHeaderLabel]',
|
||||
|
||||
@ -13,11 +13,10 @@ import {
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
import { IListable, ListingModes, TableColumnConfig } from '../models';
|
||||
import { Id, IListable, ListingModes, TableColumnConfig } from '../models';
|
||||
import { ListingComponent } from '../listing-component.directive';
|
||||
import { EntitiesService } from '../services';
|
||||
import { TableContentComponent } from '../table-content/table-content.component';
|
||||
import { Id } from '../models/trackable';
|
||||
|
||||
const SCROLLBAR_WIDTH = 11;
|
||||
|
||||
|
||||
@ -4,8 +4,7 @@ import { SortingService } from '../sorting';
|
||||
import { EntitiesService, ListingService } from './services';
|
||||
import { forwardRef, Provider, Type } from '@angular/core';
|
||||
import { ListingComponent } from './listing-component.directive';
|
||||
import { IListable } from './models';
|
||||
import { Id } from './models/trackable';
|
||||
import { Id, IListable } from './models';
|
||||
|
||||
export const DefaultListingServices: readonly Provider[] = [FilterService, SearchService, SortingService, ListingService] as const;
|
||||
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { IListable } from '../listing';
|
||||
import { Id, IListable } from '../listing';
|
||||
import { shareDistinctLast } from '../utils';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
|
||||
@Injectable()
|
||||
export class SearchService<T extends IListable<PrimaryKey>, PrimaryKey extends Id = T['id']> {
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { filter, map, startWith } from 'rxjs/operators';
|
||||
import { Entity } from '../listing';
|
||||
import { Entity, Id } from '../listing';
|
||||
import { List, RequiredParam, shareLast, Validate } from '../utils';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
import { isArray } from '../permissions';
|
||||
|
||||
@Injectable()
|
||||
|
||||
@ -3,9 +3,8 @@ import { BehaviorSubject } from 'rxjs';
|
||||
import { SortingOption } from './models/sorting-option.model';
|
||||
import { SortingOrder, SortingOrders } from './models/sorting-order.type';
|
||||
import { KeysOf, shareDistinctLast } from '../utils';
|
||||
import { IListable } from '../listing';
|
||||
import { Id, IListable } from '../listing';
|
||||
import { orderBy } from 'lodash-es';
|
||||
import { Id } from '../listing/models/trackable';
|
||||
|
||||
@Injectable()
|
||||
export class SortingService<T extends IListable<PrimaryKey>, PrimaryKey extends Id = T['id']> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user