Reputation: 377
I'm using Angular Material's table to display a list of employees coming from an observable stream.
<table mat-table [dataSource]="employees$ | async" matSort class="mat-elevation-z8"
(matSortChange)="onMatSortChange($event)" matSortDisableClear>
...
</table>
As you can see, I'm implementing my own sort function that is triggered when a user clicks on one of the column headers. Based on this event, I need to sort the elements in the table. Right now I have this:
onMatSortChange(sort: Sort): void {
const { active, direction } = sort;
const compareFn = (a: Employee, b: Employee) => {
console.log(direction);
if (direction === 'asc') {
if (a[active] > b[active]) { return 1; }
if (a[active] < b[active]) { return -1; }
return 0;
} else if (direction === 'desc') {
if (a[active] < b[active]) { return 1; }
if (a[active] > b[active]) { return -1; }
return 0;
}
};
this.employees$ = this.employees$.pipe(map(results => results.sort(compareFn)));
}
Now this appears to work correctly but I don't believe I should be reassigning the observable like this. I have a console log in my compareFn that prints one more time every time I click a column header (every time I click it, I see the output for all the clicks so far).
Is there an rxjs operator I should be using instead to get the desired result?
Upvotes: 0
Views: 256
Reputation: 702
You're right that you shouldn't reassign the observable reference. To do this, I would express your sorts as an observable Subject that emits a new sort object whenever the button is clicked. You can merge that sort stream into your main employee one. Something like this...
sorts$ = new Subject<Sort>();
employees$ = this.employeeService.get().pipe(
withLatestFrom(this.sorts$), // or mergeMap() depending on desired behavior
map(([employees, sort]) => {
// your sort logic here
return sortedEmployees;
})
);
onMatSortChange(sort: Sort): void {
this.sorts$.next(sort);
}
Upvotes: 1