Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Combine Observable with ReplaySubject

In my project I want to call an api using Observables and then with the power of ReplaySubject, I want to remember the results of it so when I revisit that page, I don’t have to call the api again. Ideally I remember the results for a set number of milliseconds which I know you can set in ReplaySubject.

One of the problems I’m aware of is the subscription can’t be on the component because it will just restart when you revisit the page again, therefore a service file would need to be used.

To start with I have my normal http.service file which should be fine as it is:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

http.service.ts

getVenuesListViaPost(filter, searchObj): Observable<any> {
  return this.http.post("api/venues/search"+filter, searchObj)
}

Then I have my component which actually shows the data. This should be fine as it is.

venues.component.ts

getData(page: number) {
        this.listedAsyncData$ = this.replayApiService.replayVenueApi(page, this.name);
 }

I’m using the async pipe on my component ie:

venues.component.html

<tr *ngFor="let item of (listedAsyncData$ | async)?.items"><td>{{item.name}}</td></tr>

So I think the problem lies with my replayApiService but I’m confused as to why this doesn’t do anything.

replay-api.service.ts

import { Injectable } from '@angular/core';
import { HttpService } from "./http.service";
import {ReplaySubject, tap} from 'rxjs';

@Injectable()
export class ReplayApiService {

    private _rememberSource = new ReplaySubject<object>(1, 200000);
    remember$ = this._rememberSource.asObservable();

    constructor(private httpService: HttpService) { }


    replayVenueApi(page, name) {
        this.httpService.getVenuesListViaPost(`?pageno=${page}&pageSize=10`, { name }).pipe(
          tap(res => this._rememberSource.next({
            "items": res.body,
            "totalPages": parseInt(res.headers.get('x-paging-pagecount'))
          }))
        ).subscribe();
      }

}

I can see the network call is made correctly, however the results don’t show on the page.

>Solution :

I suggest you refactor replayVenueApi as follows:

replayVenueApi(page, name) {
  this.httpService.getVenuesListViaPost(`?pageno=${page}&pageSize=10`, { name }).pipe(
    tap(res => this._rememberSource.next({
      "items": res.body,
      "totalPages": parseInt(res.headers.get('x-paging-pagecount'))
    }))
  ).subscribe();
}

This doesn’t implement your "don’t repeat request if it has been less than 20s", but it does mean that your ReplaySubject will emit.

In your component, you need to use the Observable, because replayVenuApi doesn’t return anything:

getData(page: number) {
  this.listedAsyncData$ = this.replayApiService.remember$;
  this.replayApiService.replayVenueApi(page, this.name);
}

For the timer element, one possible approach is to store a timestamp and compare it to the Date.now() of each call to replayVenueApi(). If the difference is less than 20 seconds, you do nothing. If it’s more, you make the request.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading