1

So I have a question about mechanics of Angular and RxJs. I have server-side pagination on my backend and I have three components on frontend: 1) list with data, 2) some filters, 3) pagination component. How do I subscribe on two streams (pagination and filters) to call getAll method with new params from this components? Perhaps I should use combineLatest operator? Its correct? How can I improve it?

const pagSettingsSub = this.paginatorSrv.subscriber$
      .pipe(
        tap(data => {
          this.pagSettings = data
        })
      )
    const filterSettingsSub = this.filterAndSortSrv.subscriber$
      .pipe(
        tap(data => this.filterAndSortSettings = data)
      )

    combineLatest([pagSettingsSub, filterSettingsSub])
      .pipe(
        tap(() => this.isLoading$.next(true)),
        mergeMap(() => this.messageSrv.getAll(this.pagSettings, this.filterAndSortSettings)),
        takeUntil(this.destroy$)
      )
      .subscribe({
        next: () => this.isLoading$.next(false),
        error: () => this.isLoading$.next(false),
        complete: () => this.isLoading$.next(false)
      })`
Air_O
  • 23
  • 5

1 Answers1

1

Yes, you can use the combineLatest operator to combine the streams from your pagination and filters components, and trigger a new request to your server whenever either of these streams emits a new value.

But since you mentioned in the comments of this answer that you will also need to reset the pagination on filter change, i would recommend that you approach it like this:

const resultData = this.filterAndSortSrv.subscriber$.pipe(
    tap(() => this.paginationSrv.resetPage()),
    switchMap((filterSettings) => combineLatest([of(filterSettings), this.paginatorSrv.subscriber$])),
    tap(() => this.isLoading$.next(true)),
    switchMap(([filterSettings, pageSettings]) => this.messageSrv.getAll(pageSettings, filterSettings)),
    takeUntil(this.destroy$),
    catchError(error => {
         // do error handling stuff
    }),
    finalize(() => this.isLoading$.next(false))
)

Here's what's happening in this code:

  1. We create two observables, one for the pagination settings and one for the filter settings. These observables emit whenever the corresponding settings are changed in the pagination and filters components.
  2. We pipe through the filter observable to always reset the pagination whenever the filter changes.
  3. We use combineLatest to combine these two observables into a single observable that emits whenever either of the component settings change.
  4. We use tap to set the isLoading$ subject to true whenever the combined observable emits.
  5. We use switchMap to make a new request to the server using the latest pagination and filter settings whenever the combined observable emits.
  6. We use takeUntil to ensure that the subscription is cancelled when the component is destroyed.
  7. Use the catchError operator to handle exceptions
  8. We use finalize to set the isLoading$ subject to false whenever the observable completes or errors.

This code should work well for your use case. However, you can also consider using debounceTime or distinctUntilChanged operators to prevent making unnecessary requests to the server if the user is typing in a filter input or changing the pagination settings frequently. These operators can help reduce the number of requests sent to the server, resulting in a more responsive and efficient user interface.

You now can use this operator with the async pipe in your html!

Don
  • 366
  • 1
  • 10
  • So helpful answer, thanks. But loading still true, whats wrong? – Air_O Apr 17 '23 at 17:37
  • I edited my answer hope it works out now! Note: https://rxjs-course.dev/course/error-handling/finalize-operator/ – Don Apr 17 '23 at 17:43
  • You save my day! And the last point I would like to clarify is how would you reset pagination when using filters? – Air_O Apr 17 '23 at 17:57
  • I suppose that by resetting the pagination you mean to reset it to page 1? You could add a method inside the paginatorSrv which resets the paginator subject (source of paginatorSrv.subscriber$). Like this: resetPagination() { this.subject.next({page: 1}); } Does this answer your question? – Don Apr 17 '23 at 18:01
  • Yes, I think the same – Air_O Apr 17 '23 at 18:05
  • I updated my answer to fit your requirements. The filter observable triggers a page reset on change now! Hope this is what you need. – Don Apr 17 '23 at 18:12