Reputation: 2732
I have a following table in my component,
<table [dataSource]="(searchResults$ | async)?.accounts" mat-table matSort multiTemplateDataRows>
<ng-container matColumnDef="Code">
<th *matHeaderCellDef mat-header-cell mat-sort-header> Account Code</th>
<td *matCellDef="let account" mat-cell> {{account.code}} </td>
</ng-container>
</table>
I have kept mat-sort directive in both the column definition and at table level.
All the examples provided in https://material.angular.io/components/table/examples - lists down dataSource when set from TS file not as observable stream.
Upvotes: 9
Views: 7109
Reputation: 673
I do realize this is a very old question (but just incase someone else needs it in the future) Like I did. This can totally be done. Start with the html as in the question above. What has an async observable response.
<table [dataSource]="(searchResults$ | async)?.accounts" mat-table matSort multiTemplateDataRows>
<ng-container matColumnDef="Code">
<th *matHeaderCellDef mat-header-cell mat-sort-header> Account Code</th>
<td *matCellDef="let account" mat-cell> {{account.code}} </td>
</ng-container>
</table>
replace it like so
<div *ngIf="{dataSource: (dataSource$ | async) } as observable">
<table
mat-table
[dataSource]="observable.dataSource"
class="mat-elevation-z8"
matSort
(matSortChange)="sortData(observable.dataSource)"
>
note either have the matSortChange call the sortData function or have that sortData function be called inside where the observable is created in the ts file (for simplicty the example shows the first way)
Then you make sure that the searchResults$ is an observable that contains a MatTableDataSource
searchResults$: Observable<any>;
searchResults$ = of(new MatTableDataSource(dataArray));
Of only used here as an example (as its not a great practice to use of in general.
Then either in the pipe if you have one or in the html add (matSortChange)="sortData(dataSource)"
private sortData(data: any) {
data.sort = this.sort;
}
and remember to add @ViewChild(MatSort) sort: MatSort;
inside the angular class
The key is that the data in dataSource has to be of MatTableDataSource for sort etc to work.
working example https://stackblitz.com/edit/angular-6fomv1-52nyue?file=app/table-basic-example.html
I should note you can also just call a subscribe on your observable in the ts file and do it all in there instead.
Upvotes: 3
Reputation: 1294
In case you need a loading(async) then after loading yo need to render the table and set the sort async. try this
component.html
<loading-component *ngIf="isLoading$ | async"></loading-component> <--WHILE Loading
<div *ngIf="!(isLoading$ | async)"> <-- AFTER Loading
<ng-container *ngIf="dataSource.data.length >= 1; else noData"> <--Check if there's data
<table mat-table [dataSource]="dataSource" matSort>
...
</table>
</ng-container>
<ng-template #noData> <- In case there is not data (to not show the table/table-header)
...
</ng-template>
</div>
component.ts
import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';
import { Observable } from 'rxjs/Observable';
export class Component {
dataSource = new MatTableDataSource<any>();
isLoading$: Observable<boolean>;
private _sort: MatSort;
@ViewChild(MatSort) set matSort(ms: MatSort) {
this._sort = ms;
this.dataSource.sort = this._sort;
}
.. the rest of the component logic ...
With the SET Sort you can fetch on the fly(async) data to table and then sort it.
Keep coding \m/
Upvotes: -1
Reputation: 199
Was just banging my head against the wall about this one for a while so putting this here to hopefully save someone some time. What worked for me:
component.ts:
@Input() dataSource;
@ViewChild(MatSort, {static: true}) sort: MatSort;
ngAfterViewInit() {
this.dataSource.subscribe(data => {
this.dataSource = new MatTableDataSource(data);
this.dataSource.sort = this.sort;
});
}
component.html:
<app-table [dataSource]="yourService.getData()"></app-table>
Make sure you don't use the async
pipe when passing the Observable to dataSource
.
I'm new to Angular, TS and RxJS (usually work with React) so if anyone sees issues with this approach let me know!
Upvotes: 0
Reputation: 10157
The same way. You will just sort the elements inside the Observable.
(matSortChange)="sortData($event)"
And then sort it:
sortData(sort: Sort) {
this.searchResults$ = this.searchResults$.pipe(map(results => {
// sort the results like in examples
}));
}
Upvotes: 1