Search code examples
angularrxjs

How to use rxjs to cancel out of a series of confirmation dialogs


I have a series of confirmation dialogs that I need to present to the user. As soon as a 'no' answer is given, I want to cancel out of the series of dialogs.

Seemed to me that the way to do this is like this:

from([dialog1,dialog2,dialog3]).pipe(
    concatMap(dialog => {
        return dialogService.confirm()
    }),
    toArray()
).subscribe(result => console.log(result))

Unfortunately, a 'no' answer doesn't cancel the series, and the result is an array representing the results of each dialog response rather than just getting the last response.

Is there a better rxjs way of handling this situation?

I used the suggestion from @Eldar:

from([dialog1,dialog2,dialog3]).pipe(
    concatMap(dialog => dialogService.confirm()),
    takeWhile(result => result==true),
    toArray()
).subscribe(result => console.log(result))

...which helped, but I'm still getting an array as the final result rather than the last value (e.g., [true, true, false], when I want just true or false). So, it still feels clunky.


Solution

  • Instead of toArray, you can use reduce to emit a single boolean when the stream completes.

    from([dialog1, dialog2, dialog3]).pipe(
        concatMap(dialog => dialogService.confirm()),
        takeWhile(result => result==true, true),
        reduce((_, result) => result),
    ).subscribe()
    

    Notice for takeWhile you need to pass true for the 'inclusive' parameter otherwise, the first false value will not get emitted.

    Since you just want to emit the most recent result, we don't need to use the accumulator in reduce, we just return the current result.

    Here's a little StackBlitz.