Angular RxJS: conditional operator (if else)
Asked Answered
H

4

12

I'm trying to figure out how to implement a straightforward condional operation into an observable.

this.deactivate$
    .pipe(
        filter((canDeactivate) => !canDeactivate),
        switchMap(() => Observable.of(window.confirm("message")))
    );

What I want to get is that:

if (canDeactivate) {
    return canDeactivate;
}
else {
    return window.confirm("message");
}

The problem on first above code is that when I'm filtering emitted value, the rest of operators are not performed and stream stops to populate emitted value.

Any ideas?

Headwork answered 4/6, 2019 at 15:8 Comment(0)
S
18

You can decide which observable return inside the switchMap operator, like this:

    this.deactivate$
        .pipe(
            switchMap((canDeactivate) => {
               if (canDeactivate) {
                   return Observable.of(canDeactivate);
               }
               else {
                   return Observable.of(window.confirm("message"));
               }
            })
        );

Bonus (super shorter version):

this.deactivate$.pipe(
        switchMap((canDeactivate) => Observable.of(canDeactivate || window.confirm("message"))
    );
Sill answered 4/6, 2019 at 15:18 Comment(2)
Or shorter, canDeactivate ? Observable.of(canDeactivate) : Observable.of(window.confirm("message"));Shepp
Sure, and more shorter if you want, what about: Observable.of(canDeactivate || window.confirm("message")) :)Logotype
E
9

From documentation of rxjs

iif Decides at subscription time which Observable will actually be subscribed.

iif accepts a condition function and two Observables. When an Observable returned by the operator is subscribed, condition function will be called. Based on what boolean it returns at that moment, consumer will subscribe either to the first Observable (if condition was true) or to the second (if condition was false). Condition function may also not return anything - in that case condition will be evaluated as false and second Observable will be subscribed.

example

let accessGranted;
const observableIfYouHaveAccess = iif(
  () => accessGranted,
  of('It seems you have an access...'),
  of('Opps')
);

So if accessGranted is true it will execute the first of else second of

Electroencephalogram answered 4/6, 2019 at 15:13 Comment(1)
iif() doesn't solve what @Headwork wants to achieve... I mean, this example shows only the theory behind the iif(), not the solution. He has an input stream, how he can merge 'this.deactivate$' with the iif()? Also, if merged inside the switchMap, it would be the same as if/else.Logotype
D
1

What about the partition operator ?

I find it more elegant when you have to deal with simple conditions and predicates: https://www.learnrxjs.io/learn-rxjs/operators/transformation/partition

It allows to split the result of an Observable into 2 Observables, the first one is executed if the given condition is valid and the other one is executed if the condition is not valid.
ex:

const [canDeactivate$, cannotDeactivate$] = partition(this.deactivate$, (canDeactivate) => !canDeactivate);
// in case the condition !canDeactivate is true
canDeactivate$.pipe(switchMap(canDeactivate => of(...)).subscribe(...);
// in case the condition !canDeactivate is false
cannotDeactivate$.pipe(switchMap(() => of(window.confirm("message")))).subscribe(...);
Deflation answered 11/8, 2022 at 14:39 Comment(0)
M
0

window.confirm is blocking so you can just use a map() operator. Calling switchMap to of(window.confirm(..)) will just stop the execution of JavaScript anyway.

this.deactivate$
    .pipe(
        map(canDeactivate => canDeactivate ? canDeactivate : window.confirm("message"))
    );
Meryl answered 4/6, 2019 at 20:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.