I have a page where user needs to select some 'entity' from a dropdown and click a button to request data. Then when the data has loaded another request will be made automatically to get more details about that data. Then if the user has activated the auto refresh, the request for details will happen every x seconds, where x is some number also configured by the user.
I am struggling to set up this observable chain. So far I have this:
// in Service file
private selectedEntitySubject = new Subject<string>();
selectedEntity$ = this.selectedEntitySubject.asObservable();
private generateButtonClickSubject = new Subject<void>();
generateButtonClick$ = this.generateButton.asObservable();
private refreshIntervalSubject = new BehaviourSubject<number>(20);
refreshInterval$ = this.refreshIntervalSubject.asObservable();
private autoRefreshOnSubject = new BehaviourSubject<boolean>(true);
autoRefreshOn$ = this.autoRefreshOnSubject.asObservable();
autoRefreshTimer$ = combineLatest([
this.refreshIntervalSubject,
this.autoRefreshOnSubject
]).pipe(
skipWhile(([intervalLength, autoRefreshOn]) => autoRefreshOn === false),
switchMap(([intervalLength]) => interval(intervalLength * 1000))
);
graphData$ = this.generateButtonClick$.pipe(
switchMap(() => this.selectedEntity$),
switchMap((selectedEntity) => this.http.get(`data?entity=${selectedEntity}`))
);
latestFullData$ = combineLatest([
this.graphData$,
this.autoRefreshTimer$
]).pipe(
switchMap(([graphData]) => this.addDetails(graphData))
);
addDetails(graphData) {
const ids = graphData.map(entry => entry.id).join(',');
return this.http.get(`details?forIds=${ids}`).pipe(
map(detailsData =>
graphData.map(entry => Object.assign(entry, {details: _.find(detailsData, {id: entry.id})}))
)
);
}
// in component file
this.graphDataService.latestFullData$.subscribe(data => {
// handle data
});
This does not work, because if the auto refresh is turned off then the latestFullData$ observable never emits.
My goal is to subscribe to just one observable in my component, that will emit data any time user clicks generate button, or auto refresh happens. Also when the user changes the interval amount, or turns on/off whether the data should auto refresh, or clicks the generate button again, the interval should start again from the beginning.
Can anyone suggest how I can handle the timer? The first part is working where the data will emit when the generate button is clicked, but I can't figure out the timer part.
If anything is unclear or I am massively overcomplicating things just let me know. Thanks for any help.
Just in case anyone has a similar problem I found a solution.
autoRefreshTimer$
needed to be changed to this:
autoRefreshTimer$ = combineLatest([
this.refreshIntervalSubject,
this.autoRefreshOnSubject,
]).pipe(
switchMap(([intervalLength, autoRefreshOn]) => {
if (autoRefreshOn) {
return interval(intervalLength * 1000);
} else {
return of(1);
}
})
);
So when the auto refresh is off it doesn't block the stream.
Not quite as elegant as I hoped but it does the job.