Using any kind of event I managed to find from the API for select and autocomplete ends up with the MatPaginator being ‘a step behind’, e.g. while the filtered data is supposed to be only 200 in length, the paginator.length is still stuck at 800, and only becomes 200 after the next selection.
.html
<mat-form-field class="filterField">
<input matInput
(keyup)="updateManualPage(1)"
placeholder="Filter"
formControlName="filterParam2"
[matAutocomplete]="autoSingleSelect">
<mat-autocomplete #autoSingleSelect="matAutocomplete"
class="filterSelect"
panelClass="filterSelect">
<mat-option *ngFor="let option of dropdownSingleFilteredOptions | async"
[value]="option.param2">
{{option.param2}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<div id="paginationContainer">
<div id="pageNumberButtons">
<button mat-button
[class.hiddenPage]="!(manualPage > 3)"
(click)="updateManualPage(1)">
1
</button>
...etc
</div>
<mat-paginator [length]="tableDataSource.data.length"
[pageSize]="10"
[pageSizeOptions]="[5, 10, 25]"
showFirstLastButtons
aria-label="Select page"
[selectConfig]="{ panelClass: 'paginatorDropdown' }"
(page)="onPaginateChange($event)">
</mat-paginator>
</div>
.ts
tableDataSource = new MatTableDataSource<randomInterface>(testArray);
maxPages: number = 0;
manualPages: number = 1;
ngOnInit() {
this.tableDataSource.filterPredicate = this.customFilter;
}
ngAfterViewInit() {
this.updatePaginator();
this.updateMaxPages();
}
onPaginateChange(event: PageEvent) {
this.manualPage = event.pageIndex + 1;
this.updatePaginator();
this.updateMaxPages();
}
updateManualPage(page: number) {
this.manualPage = page;
this.tableDataSource.paginator!.pageIndex = page - 1;
this.updatePaginator();
this.updateMaxPages();
}
updatePaginator() {
this.tableDataSource.paginator = this.paginator;
}
updateMaxPages() {
this.maxPages = Math.ceil((this.tableDataSource.paginator?.length ?? 0) / (this.tableDataSource.paginator?.pageSize ?? 1));
}
customFilter = (data: randomInterface, filter: string) => {
const filterData = JSON.parse(filter);
let find: boolean = !filterData.filterParam1 || data.param1.toString().includes(filterData.filterParam1.toString());
find = find && (!filterData.filterParam2 || data.param2.toLowerCase().includes(filterData.filterParam2.toLowerCase()));
find = find && (!filterData.filterParam3 || filterData.filterParam3 == '' ? true : filterData.filterParam3.some((filterValue: string) => filterValue.toLowerCase() == data.param3.toLowerCase()));
return find;
}
I’ve tried updating this.maxPages
at multiple different points in the .ts code, but no matter where I put it and which event I use on the HTML side, the paginator itself is always lagging behind, and I’m personally unsure of how to use, and if it would even help, to use ._updatePaginator(filteredDataLength: number)
since I am using a predicate to filter the data. It used to not work for the elements either, at least with (keydown)
and (input)
events since they, for the lack of a better word, ‘too fast’ for the paginator, while (keyup)
worked perfectly.
EDIT: After doing some exploring it seems that while the this.tableDataSource.Paginator
is updating, and comes before the call for updateManualPage(1)
on the autocomplete event, for some reason this.maxPages
still stays the same.
Doing
updateMaxPages() {
console.log(this.tableDataSource);
this.maxPages = Math.ceil((this.tableDataSource.paginator?.length ?? 0) / (this.tableDataSource.paginator?.pageSize ?? 1));
}
shows that the paginator is indeed updating, the literal next line is for some reason a whole call behind.
2
Answers
Setting a timeout of 0
has 'fixed' it but for some reason I feel like this is going to create a lot of problems in the future. Any input is welcome!
If you use a mat-table and you’re not using an API to filter, you needn’t make anything with the paginator (material makes the work for you). See the example "Data table with sorting, pagination, and filtering." in the docs
BTW when yo do
use
In this way you don’t need makes each time the toLowerCase…
NOTE: The setTimeout without miliseconds force to Angular to repaint. It’s necessary because this.tableDataSource.paginator?.length has no the correct value when you executed directly and is perfectly valid (well, really not because it’s not necessary recalculate manually.)