Merge pull request #5065 from tsiegleauq/apply-search-filter-bug

Refresh DataSource filter and sort
This commit is contained in:
Emanuel Schütze 2019-10-02 14:21:46 +02:00 committed by GitHub
commit aab7a41efd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 136 additions and 107 deletions

View File

@ -11,10 +11,11 @@ import {
ViewEncapsulation ViewEncapsulation
} from '@angular/core'; } from '@angular/core';
import { columnFactory, createDS, PblDataSource, PblNgridComponent } from '@pebula/ngrid'; import { columnFactory, createDS, DataSourcePredicate, PblDataSource, PblNgridComponent } from '@pebula/ngrid';
import { PblColumnDefinition, PblColumnFactory, PblNgridColumnSet } from '@pebula/ngrid/lib/table'; import { PblColumnDefinition, PblColumnFactory, PblNgridColumnSet } from '@pebula/ngrid/lib/table';
import { PblNgridDataMatrixRow } from '@pebula/ngrid/target-events'; import { PblNgridDataMatrixRow } from '@pebula/ngrid/target-events';
import { Observable } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
import { OperatorService, Permission } from 'app/core/core-services/operator.service'; import { OperatorService, Permission } from 'app/core/core-services/operator.service';
import { StorageService } from 'app/core/core-services/storage.service'; import { StorageService } from 'app/core/core-services/storage.service';
@ -223,10 +224,15 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
public dataSourceChange = new EventEmitter<PblDataSource<V>>(); public dataSourceChange = new EventEmitter<PblDataSource<V>>();
/** /**
* test data source * Table data source
*/ */
public dataSource: PblDataSource<V>; public dataSource: PblDataSource<V>;
/**
* Observable to the raw data
*/
private dataListObservable: Observable<V[]>;
/** /**
* Minimal column width * Minimal column width
*/ */
@ -252,17 +258,16 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
*/ */
public inputValue: string; public inputValue: string;
/**
* Flag to indicate, whether the table is loading the first time or not.
* Otherwise the `DataSource` will be empty, if there is a query stored in the local-storage.
*/
private initialLoading = true;
/** /**
* Private variable to hold all classes for the virtual-scrolling-list. * Private variable to hold all classes for the virtual-scrolling-list.
*/ */
private _cssClasses: CssClassDefinition = {}; private _cssClasses: CssClassDefinition = {};
/**
* Collect subsciptions
*/
private subs: Subscription[] = [];
/** /**
* Most, of not all list views require these * Most, of not all list views require these
*/ */
@ -273,7 +278,6 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
label: '', label: '',
width: '40px' width: '40px'
}, },
{ {
prop: 'projector', prop: 'projector',
label: '', label: '',
@ -391,86 +395,34 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
}); });
} }
public ngOnInit(): void { public async ngOnInit(): Promise<void> {
// Create ans observe dataSource this.getListObservable();
await this.restoreSearchQuery();
this.createDataSource();
this.changeRowHeight();
this.scrollToPreviousPosition();
this.cd.detectChanges();
}
/**
* Stop the change detection
*/
public ngOnDestroy(): void {
this.cd.detach();
for (const sub of this.subs) {
sub.unsubscribe();
}
this.subs = [];
}
/**
* Function to create the DataSource
*/
private createDataSource(): void {
this.dataSource = createDS<V>() this.dataSource = createDS<V>()
.onTrigger(() => { .onTrigger(() => (this.dataListObservable ? this.dataListObservable : []))
let listObservable: Observable<V[]>;
if (this.repo && this.viewModelListObservable) {
if (this.filterService && this.sortService) {
// filtering and sorting
this.filterService.initFilters(this.viewModelListObservable);
this.sortService.initSorting(this.filterService.outputObservable);
listObservable = this.sortService.outputObservable;
} else if (this.filterService) {
// only filter service
this.filterService.initFilters(this.viewModelListObservable);
listObservable = this.filterService.outputObservable;
} else if (this.sortService) {
// only sorting
this.sortService.initSorting(this.viewModelListObservable);
listObservable = this.sortService.outputObservable;
} else {
// none of both
listObservable = this.viewModelListObservable;
}
}
return listObservable ? listObservable : [];
})
.create(); .create();
const filterPredicate = (item: V): boolean => {
if (!this.inputValue) {
return true;
}
if (this.inputValue) {
// filter by ID
const trimmedInput = this.inputValue.trim().toLowerCase();
const idString = '' + item.id;
const foundId =
idString
.trim()
.toLowerCase()
.indexOf(trimmedInput) !== -1;
if (foundId) {
return true;
}
// custom filter predicates
if (this.filterProps && this.filterProps.length) {
for (const prop of this.filterProps) {
if (item[prop]) {
let propertyAsString = '';
// If the property is a function, call it.
if (typeof item[prop] === 'function') {
propertyAsString = '' + item[prop]();
} else if (item[prop].constructor === Array) {
propertyAsString = item[prop].join('');
} else {
propertyAsString = '' + item[prop];
}
if (!!propertyAsString) {
const foundProp =
propertyAsString
.trim()
.toLowerCase()
.indexOf(trimmedInput) !== -1;
if (foundProp) {
return true;
}
}
}
}
}
}
};
this.dataSource.setFilter(filterPredicate);
// inform listening components about changes in the data source // inform listening components about changes in the data source
this.dataSource.onSourceChanged.subscribe(() => { this.dataSource.onSourceChanged.subscribe(() => {
this.dataSourceChange.next(this.dataSource); this.dataSourceChange.next(this.dataSource);
@ -490,21 +442,51 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
.table(...this.defaultStartColumns, ...this.columns, ...this.defaultEndColumns) .table(...this.defaultStartColumns, ...this.columns, ...this.defaultEndColumns)
.build(); .build();
// Sets the row height. this.dataSource.setFilter(this.getFilterPredicate());
this.changeRowHeight();
// restore scroll position // refresh the data source if the filter changed
if (this.listStorageKey) { if (this.filterService) {
this.scrollToPreviousPosition(this.listStorageKey); this.subs.push(
this.restoreSearchQuery(this.listStorageKey); this.filterService.outputObservable.pipe(distinctUntilChanged()).subscribe(() => {
this.dataSource.refresh();
})
);
}
// refresh the data source if the sorting changed
if (this.sortService) {
this.subs.push(
this.sortService.outputObservable.subscribe(() => {
this.dataSource.refresh();
})
);
} }
} }
/** /**
* Stop the change detection * Determines and sets the raw data as observable lists according
* to the used search and filter services
*/ */
public ngOnDestroy(): void { private getListObservable(): void {
this.cd.detach(); if (this.repo && this.viewModelListObservable) {
if (this.filterService && this.sortService) {
// filtering and sorting
this.filterService.initFilters(this.viewModelListObservable);
this.sortService.initSorting(this.filterService.outputObservable);
this.dataListObservable = this.sortService.outputObservable;
} else if (this.filterService) {
// only filter service
this.filterService.initFilters(this.viewModelListObservable);
this.dataListObservable = this.filterService.outputObservable;
} else if (this.sortService) {
// only sorting
this.sortService.initSorting(this.viewModelListObservable);
this.dataListObservable = this.sortService.outputObservable;
} else {
// none of both
this.dataListObservable = this.viewModelListObservable;
}
}
} }
/** /**
@ -514,6 +496,58 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
this.cd.markForCheck(); this.cd.markForCheck();
} }
/**
* @returns the filter predicate object
*/
private getFilterPredicate(): DataSourcePredicate {
return (item: V): boolean => {
if (!this.inputValue) {
return true;
}
// filter by ID
const trimmedInput = this.inputValue.trim().toLowerCase();
const idString = '' + item.id;
const foundId =
idString
.trim()
.toLowerCase()
.indexOf(trimmedInput) !== -1;
if (foundId) {
return true;
}
// custom filter predicates
if (this.filterProps && this.filterProps.length) {
for (const prop of this.filterProps) {
if (item[prop]) {
let propertyAsString = '';
// If the property is a function, call it.
if (typeof item[prop] === 'function') {
propertyAsString = '' + item[prop]();
} else if (item[prop].constructor === Array) {
propertyAsString = item[prop].join('');
} else {
propertyAsString = '' + item[prop];
}
if (!!propertyAsString) {
const foundProp =
propertyAsString
.trim()
.toLowerCase()
.indexOf(trimmedInput) !== -1;
if (foundProp) {
return true;
}
}
}
}
}
};
}
/** /**
* Generic click handler for rows. Allow so (multi) select anywhere * Generic click handler for rows. Allow so (multi) select anywhere
* @param event the clicked row * @param event the clicked row
@ -557,11 +591,7 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
this.saveSearchQuery(this.listStorageKey, filterValue); this.saveSearchQuery(this.listStorageKey, filterValue);
} }
this.inputValue = filterValue; this.inputValue = filterValue;
if (this.initialLoading) { this.dataSource.syncFilter();
this.initialLoading = false;
} else {
this.dataSource.syncFilter();
}
} }
/** /**
@ -590,8 +620,8 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
* *
* @param key The `StorageKey` for the list-view. * @param key The `StorageKey` for the list-view.
*/ */
public async restoreSearchQuery(key: string): Promise<void> { public async restoreSearchQuery(): Promise<void> {
this.inputValue = await this.store.get<string>(`query_${key}`); this.inputValue = await this.store.get<string>(`query_${this.listStorageKey}`);
} }
/** /**
@ -604,10 +634,9 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
* Furthermore, dynamic assigning the amount of pixels in vScrollFixed * Furthermore, dynamic assigning the amount of pixels in vScrollFixed
* does not work, tying the tables to the same hight. * does not work, tying the tables to the same hight.
*/ */
public scrollToPreviousPosition(key: string): void { public async scrollToPreviousPosition(): Promise<void> {
this.getScrollIndex(key).then(index => { const scrollIndex = await this.getScrollIndex(this.listStorageKey);
this.ngrid.viewport.scrollToIndex(index); this.ngrid.viewport.scrollToIndex(scrollIndex);
});
} }
/** /**