Merge pull request #5065 from tsiegleauq/apply-search-filter-bug
Refresh DataSource filter and sort
This commit is contained in:
commit
aab7a41efd
@ -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);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user