2

The following code effectively maps promise resolution to true and a promise error to false.

onlineUpdate$
.switchMap(online => {
  switch (online) {
    default:
    case true: {
      const connected$ = new Rx.Subject();
      axios.get("/some/url/to/test/connection")
        .then(response => connected$.next(true))
        .catch(error => connected$.next(false));
      return connected$;
    }
    case false: {
      return Rx.Observable.of(false);
    }
  }
});

But something about creating the intermediate Rx.Subject feels like I'm doing more work than I need to. Is there a more elegant or built-in way to map promise resolution to one value and promise error to another without the use of an intermediate Rx.Subject or other observable?

Chris Calo
  • 7,518
  • 7
  • 48
  • 64
  • While in this particular case not much can happen, I still would [recommend `.then(…, …)` over `.then(…).catch(…)`](https://stackoverflow.com/q/24662289/1048572) – Bergi Nov 20 '17 at 05:38

4 Answers4

3

Wrap the Promise into an Observable via Observable#fromPromise function and pass the the promise into. Observable will emit true if the Promise is resolved or false if it is rejected

...
case true: {
      return Rx.Observable.fromPromise(axios.get("/some/url/to/test/connection")
                                            .then(response => true)
                                            .catch(error => false));
    }
...

Simple Example.

Rx.Observable.of(false) is equivalent to the case false. Promise.resolve(true) to the then function of the promise and Promise.reject('Error').catch(err => false) to the catch function of the promise.

Rx.Observable.of(false).subscribe(console.log);
Rx.Observable.fromPromise(Promise.resolve(true)).subscribe(console.log);
Rx.Observable.fromPromise(Promise.reject('Error').catch(err => false)).subscribe(console.log);
<script src="https://unpkg.com/@reactivex/rxjs@5.5.2/dist/global/Rx.js"></script>
Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112
  • 1
    Thanks for the answer, @Suren. This indeed helped me get rid of the Rx.Subject(). However, it turns out the use of `Observable.fromPromise` isn't needed with `flatMap` or `switchMap`. – Chris Calo Nov 20 '17 at 03:50
1

Yes, you can just return Observable.of(false) in the catch block of the Observable.fromPromise(). Like wise, use .map() to return Observable.of(true) if the connection is successful.

onlineUpdate$
    .switchMap(online => {
        switch (online) {
            default:
            case true: {
                Rx.Observable.fromPromise(axios.get("/some/url/to/test/connection"))
                    .map(() => true) // if the promise resolves to something, return an Observable.of(true)
                    .catch(() => Rx.Observable.of(false)) // else if there is any error return Observable.of(false)
            }
            case false: {
                return Rx.Observable.of(false);
            }
        }
    });

Note that you have to explicitly .map() the Observable.fromPromise to true if the promise resolves successfully.

You can write the code in a much more succinct way:

onlineUpdate$
    .switchMap(online => {
        return online ?
            Rx.Observable.fromPromise(axios.get("/some/url/to/test/connection"))
                .map(() => true)
                .catch(() => Observable.of(false))
            : Observabe.of(false)
    });
CozyAzure
  • 8,280
  • 7
  • 34
  • 52
1

The switchMap operator works with so-called Observable input which means you can just return the Promise without turning it into an Observable:

onlineUpdate$
.switchMap(online => {
  switch (online) {
    default:
    case true: {
      return axios.get("/some/url/to/test/connection");
    }
    case false: {
      return Rx.Observable.of(false);
    }
  }
})
.catch(() => Rx.Observable.of(false))
.map(Boolean) // force convert to boolean

Just be aware this isn't the same as what you wrote. The catch operator will catch all errors even if they don't come from the preceding axios.get call but maybe it doesn't matter in your case.

martin
  • 93,354
  • 25
  • 191
  • 226
1

It turns out there's no need to use Observable.fromPromise() at all. The most straightforward change to make this work is:

onlineUpdate$
.switchMap(online => {
  switch (online) {
    default:
    case true: {
      return axios.get("/some/url/to/test/connection")
        .then(response => true)
        .catch(error => false);
    }
    case false: {
      return Rx.Observable.of(false);
    }
  }
});

Or, if you prefer ternaries over switch statements:

onlineUpdate$
.switchMap(online => {
  return online ?
    axios.get("/some/url/to/test/connection")
      .then(response => true)
      .catch(error => false)
    : Rx.Observable.of(false);
});
Chris Calo
  • 7,518
  • 7
  • 48
  • 64