Mat-Table Selection only on current PageSize?
My solution is based on currently displayed rows so it works regarding the pagination. There is a lot to improve about it so please feel free to make it better.
isAllSelected() {
const numSelected = this.selection.selected.length;
const displayedRows = this.filteredEvents.connect().value.length;
let isAllSelected = (numSelected === displayedRows);
if (isAllSelected) {
isAllSelected = this.isAllDisplayedSelected();
}
return isAllSelected;
}
isAllDisplayedSelected() {
let isAllDisplayedSelected = true;
if (this.selection.selected.length === 0) {
return this.isAllSelected();
}
this.filteredEvents.connect().value.some(element => {
if (!this.selection.isSelected(element)) {
isAllDisplayedSelected = false;
return isAllDisplayedSelected;
}
});
return isAllDisplayedSelected;
}
masterToggle() {
this.isViewableSelected() ?
this.deselectRows() :
this.selectRows();
}
isViewableSelected() {
return (this.isAllSelected() || this.isAllDisplayedSelected());
}
deselectRows() {
const itemsToBeUnselected = this.filteredEvents.connect().value;
itemsToBeUnselected.forEach(element => {
this.selection.deselect(element);
});
}
selectRows() {
const currentlyDisplayedRows = this.filteredEvents.connect().value;
for (let index = 0; index < currentlyDisplayedRows.length; index++) {
this.selection.select(currentlyDisplayedRows[index]);
this.selectionAmount = this.selection.selected.length;
}
}
The HTML:
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selection.hasValue() && isViewableSelected()"
[indeterminate]="selection.hasValue() && !isViewableSelected()">
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)">
</mat-checkbox>
</td>
</ng-container>
Here is my solution. https://angular-vkz1dp.stackblitz.io I build in an extra if switch page it will uncheck.
HTML column:
<mat-checkbox #ref
(click)="$event.stopPropagation()"
(change)="$event ? masterToggle(ref) : null"></mat-checkbox>
HTML cell:
<mat-checkbox (click)="$event.stopPropagation()"
[checked]="selection.isSelected(element)"></mat-checkbox>
HTML paginator:
<mat-paginator fixed [pageSizeOptions]="[20, 50, 100]" [pageSize]="20" (page)="pageChange()" showFirstLastButtons></mat-paginator>
Component:
@ViewChild('ref') ref: any;
masterToggle(_ref: any) {
if(_ref.checked){
this.checkPageOnly();
}
else {
this.selection.clear();
}
}
checkPageOnly() {
let i = this.dataSource.paginator.pageIndex * this.dataSource.paginator.pageSize;
let end = (this.dataSource.paginator.pageIndex + 1) * this.dataSource.paginator.pageSize;
for(i; i < end; i++) {
this.selection.select(this.dataSource.data[i]);
}
}
pageChange() {
this.ref.checked = false;
this.masterToggle(this.ref);
}
}
If you're using sorting, paginating, and filtering:
HTML column:
<mat-checkbox (change)="$event ? masterToggle($event) : null"
[checked]="selection.hasValue() && isEntirePageSelected()"
[indeterminate]="selection.hasValue() && !isEntirePageSelected()"
[aria-label]="checkboxLabel()"></mat-checkbox>
Component:
getPageData() {
return this.dataSource._pageData(this.dataSource._orderData(this.dataSource.filteredData));
}
isEntirePageSelected() {
return this.getPageData().every((row) => this.selection.isSelected(row));
}
masterToggle(checkboxChange: MatCheckboxChange) {
this.isEntirePageSelected() ?
this.selection.deselect(...this.getPageData()) :
this.selection.select(...this.getPageData());
}
checkboxLabel(row): string {
if (!row) {
return `${this.isEntirePageSelected() ? 'select' : 'deselect'} all`;
}
return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.id + 1}`;
}
Was able to get it to work by removin the last line on the masterToggle()
method, and replacing that with a custom function that loops through the PageSize of the paginator and calls the select
method of the SelectionModel
for each alert it finds; I also changed the isAllSelected
method to compare the PageSize
and the selected lenght
instead of the whole dataSource
.
/** Whether the number of selected elements matches the total number of rows. */
isAllSelected() {
const numSelected = this.selection.selected.length;
const page = this.dataSource.paginator.pageSize;
return numSelected === page;
}
/** Selects all rows if they are not all selected; otherwise clear selection. */
masterToggle() {
this.isAllSelected() ?
this.selection.clear() : this.selectRows();
}
selectRows() {
for (let index = 0; index < this.dataSource.paginator.pageSize; index++) {
this.selection.select(this.dataSource.data[index]);
this.selectionAmount = this.selection.selected.length;
}
}