Haskell
Haskell

Reputation: 377

How can I change data returned from observable while the subscription is active?

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

Answers (1)

Adam Dunkerley
Adam Dunkerley

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

Related Questions