Working on a web application using Angular 10 has led me to prefer Observables over Promises. However, creating a seamless flow of executions can be challenging at times.
My objective is to follow this flow:
- Show a confirmation modal
- If the confirmation returns a value (
{isConfirmed: true}
), display a loading screen (based on the condition). - Utilize
switchMap
to initiate HTTP calls. - If any HTTP call fails, hide the loading screen and display a warning message.
My Approach:
send(title: string, message): Observable<any> {
const isConfirmed: Promise<{isConfirmed: boolean}> = this.alertService.warningConfirmation(
'Send message',
'Are you sure you want to send the message?',
'Send',
'Cancel'
);
return from(isConfirmed)
.pipe(
tap(res => res.isConfirmed ? this.loadingService.present() : EMPTY),
switchMap(res => from(this.service.httpCallOneGetUsers())
.pipe(
map(users => users.map(user => user.email)),
switchMap(emails => this.service.httpCallTwoSendMessage(title, message, emails))
)
),
finalize(() => this.loadingService.dismiss()),
tap({
next: () => console.log('Message sent!'),
error: () => console.log('Could not send the message.')
})
);
}
When canceling the confirmation, the error event is triggered without displaying the loading screen.
The first switchMap
contains two HTTP calls, one returning a Promise and the other an Observable. This is why I used from()
for the first call.
My Objectives are:
- To conditionally enter the
switchMap
if the confirmation result isisConfirmed: true
. If false, abort the process without triggering the error event. - To determine the optimal placement for
tap
orfinalize
to handle showing/hiding the loading screen and displaying success/error messages to the user.