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:
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.
CodePudding user response:
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.