Reputation: 2603
I am trying to make one of my data tables to use a default sorting capabilities. I am using angular material table an MatSoftModule for it.
Now, I have pretty simple data loading from the API. In my controller, I am calling a service function that returns Observable:
export class DomainComponent implements OnInit {
domains$: Observable<Domain[]>;
columnsToDisplay = ['id', 'title'];
constructor(private domainService: DomainService) { }
ngOnInit() {
this.loadDomains();
}
private loadDomains() {
this.domains$ = this.domainService.getDomains();
}
}
And in the view I am simply using that observable as dataSource:
<table mat-table [dataSource]="domains$" matSort matSortActive="id" matSortDirection="asc" class="mat-elevation-z4">
<!-- Id Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> No. </th>
<td mat-cell *matCellDef="let element" class="td-id"> {{element.id}} </td>
</ng-container>
<!-- Title Column -->
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Title </th>
<td mat-cell *matCellDef="let element" class="td-title"> {{element.title}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay"></tr>
</table>
The table itself works perfectly fine, and in this case, the headers are even shown as sortable (and even clickable). However, the sorting does not actually change.
From the documentation: https://material.angular.io/components/table/overview#sorting
It looks like I need to listen to "bind" sort
function of dataSource to matSort. But, the documentation is talking about simple array of objects.
What is the simplest way to make the sorting to work without some craziness of custom DataSource implementation as described here: https://blog.angular-university.io/angular-material-data-table/ ?
Upvotes: 3
Views: 3623
Reputation: 73751
You can sort the Observable data with the map
operator. In ngOnInit
, you pass the initial sort order as a parameter to loadDomains
:
import { map } from "rxjs/operators";
import { Sort } from "@angular/material";
ngOnInit() {
this.loadDomains({active: "id", direction: "asc"});
}
loadDomains(sort: Sort) {
this.domains$ = this.domainService.getDomains().pipe(
map((domains: Array<Domain>) => domains.sort((d1, d2) => this.sortDomains(d1, d2, sort)))
);
}
sortDomains(d1: Domain, d2: Domain, sort: Sort) {
const one = sort.direction === "asc" ? 1 : (sort.direction === "desc" ? -1 : 0);
if (d1[sort.active] > d2[sort.active]) {
return one;
} else if (d1[sort.active] < d2[sort.active]) {
return -one;
} else {
return 0;
}
}
In the template, you call loadDomains
with the new sort order in the matSortChange
event handler:
<table mat-table
class="mat-elevation-z4"
[dataSource]="domains$"
matSort
matSortActive="id"
matSortDirection="asc"
(matSortChange)="loadDomains($event)">
You can see a demo in this stackblitz, based on the original stackblitz provided by @AlexHaslam.
Upvotes: 3