Я понял, как настроить таблицу для моих требований.Основное изменение состоит в том, что я удалил Observable, который выбирает данные из TableDataSource , и ввел DataService :
export class DataService {
//the @Select is from ngxs but can be anything returning an Observable
@Select(TokenTableState.getTokenTableItems) private tokenTableItems$: Observable<TokenTableViewItem[]>;
private initValue$: BehaviorSubject<TokenTableViewItem[]> = new BehaviorSubject<TokenTableViewItem[]>([]);
getAllItems(): Observable<TokenTableViewItem[]> {
const sources = [this.tokenTableItems$, this.initValue$];
return merge(...sources);
}
}
По сути, эта служба получает данные из любогоНаблюдаемый ввод и объединение его в методе getAllItems с начальным значением.
Компонент имеет экземпляр этой службы:
private _dataService: DataService | null;
, который он передает TableDatasource в методе загрузки:
private loadData(): any {
this._dataService = new DataService();
this.dataSource = new TokenTableDataSource(
this._dataService,
this.paginator,
this.sort
);
fromEvent(this.filter.nativeElement, 'keyup').subscribe(() => {
if (!this.dataSource) {
return;
}
this.dataSource.filter = this.filter.nativeElement.value;
});
}
Причина, по которой у меня нет ссылки на DataService в TableDataSource означает, что paginator в Component требуется длина таблицы для рендеринга (см. ниже).
TableDataSource использует DataService следующим образом:
В методе connect он содержит массив с возможными мутациями данных:
const dataMutations = [
this._dataChange,
this._sort.sortChange,
this._filterChange,
this._paginator.page
];
Член массива _dataChange получаетэто значение, подписавшись на метод getAllItems из нашего DataService :
this._internalService.getAllItems().subscribe(data => {
this._dataChange.next(data);
});
dataMutations используются какэто для фильтрации, сортировки и возврата данных, которые должны отображаться:
return merge(...dataMutations).pipe(
map(() => {
// Filter data
this.filteredData = this._dataChange.value
.slice()
.filter((item: TokenTableViewItem) => {
const searchStr = (item.symbol + item.name).toLowerCase();
return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
});
// Sort filtered data
const sortedData = this.getSortedData(this.filteredData.slice());
// Grab the page's slice of the filtered sorted data.
this.renderedData = this.getPagedData(sortedData);
return this.renderedData;
})
);
filterChange определяется в локальном экземпляре
_filterChange = new BehaviorSubject('');
, в то время как нумерация страниц и сортировка запускаются извне через конструктор
constructor(
public _internalService: DataService,
public _paginator: MatPaginator,
public _sort: MatSort
) {
super();
this._filterChange.subscribe(() => (this._paginator.pageIndex = 0));
}
Я также нашел решение для нумерации страниц, котороеопределяется в component.html следующим образом:
<mat-paginator #paginator
[length]="dataSource.filteredData.length"
[pageIndex]="pageIndex"
[pageSize]="pageSize"
[pageSizeOptions]="pageSizeOptions"
[showFirstLastButtons]=true>
</mat-paginator>
и с переменными, установленными в component.ts :
pageSizeOptions = [5, 10, 20, 40];
pageSize = this.pageSizeOptions[0];
pageIndex = 0;
Полный код можно увидеть на этом проекте, а живая версия таблицы используется на whatsmytoken.com .