In my current situation, I encountered the following scenario:
I have a service that makes Http calls to an API and requires access to user data to set the authentication header.
Below is the function that returns the observable used in the template:
getBillingReport(date: Date) {
return this.auth.userObs$.pipe(
switchMap((userData) => {
const header = this.utils.createAuthHeader(userData);
return this.http.get<BillingReport>(
`${
environment.apiBase
}/reports/billing?${this.utils.monthYearQuery(date)}`,
{ headers: header }
);
})
);
}
This function takes a date parameter, so I created a Date BehaviorSubject to switchMap into this function and retrieve the data.
billingReport$ = this.selectedDate$.pipe(
tap(() => {
this.loadingResults = true;
}),
switchMap((date) => {
return this.reports.getBillingReport(date);
}),
tap(() => {
this.loadingResults = false;
})
);
Everything functions correctly as the data reacts to changes in the selectedDate and the User observable. However, when attempting to implement a loading state, issues arise.
I tried using tap before the switchMap to set a boolean to true for a loading state. This approach only works if 'selectedDate$' emits (if the date changes). If the user observable emits, then only the last tap is executed, failing to create the desired loading effect.
Is there a way to ensure both events set the flag to true with this current setup? Or should I explore other solutions? Removing the switchMap from the service function may solve the problem, but every component would require something like this:
billingReport$ = this.auth.userObs$.pipe(
tap(() => this.loadingResults = true),
switchMap((userData) => {
return this.selectedDate$.pipe(
tap(() => this.loadingResults = true),
switchMap((date) => {
return this.reports.getBillingReport(date);
})
)
}),
tap(() => this.loadingResults = false),
);
This approach might not be ideal since similar behavior exists in multiple components. Perhaps there's a better solution?
Note: I am utilizing the async pipe for subscription in the template.