I want to export a file containing a list of data when the user clicks a button. I have an observable (user$) which contains the user's identity. If the user is not authorised to get this data, they will be redirected to another page. If the user is indeed authorised, then the data is retrieved from the back-end and exported into a spreasheet (this part doesn't matter, I know how to do it). The title of the file depends on the identity of the user.
I am stuck at:
onClick(){
this.user$.pipe(
tap((user: User) => {
if (!user.isAuthorised) {
this.router.navigate(["/someOtherPage"]);
}
}),
switchMap((user: User) => {
let myData$: Observable<Array<Data>> =
this.myDataService.getDataByUserName(user.name);
this.exportService.exportFile(myData$, user.name);
})
);
}
The exportFile(Array, string) method needs the data to be exported as input, and it needs the name of the user to form the title of the spreasheet. How do I combine all these observables in a clean and efficient way?
Picci is correct that you should return EMPTY so that observable is completed. Also, in 99% of cases, I agree that you should only perform side effects inside of
tapoperator, so that it's clear a side effect is happening.However, in this case the code is somewhat simple, so I think you can get away with the router navigation within a guard clause that returns
EMPTY. As for getting thedataand theuserin the same scope for you call toexportService.exportFile(), you can simply add a.pipe()onto your first call tomyDataService.getDataByUserName:It's sometimes handy to pass data from the view, to your controller methods. If the view happens to have access to the current user, you could pass to your
onClick()method. This would simplify things a bit:Here we don't need to subscribe to
user$to get the user, since it's passed it. This means we don't even involve observables at all when the user is not authorized. In the case they are authorized, we only need a singleswitchMapsince we only use 2 observables, instead of 3.One last alternative, assuming the view model has the current user, is to put the conditional in the template, and break up your
onClickmethod into to smaller methods:downloadFileandgoToOtherPage: