How do I resolve an Observable inside of another Observable? - rxjs

19,810

Solution 1

Did you try the following (Also untested):

function getMe(accessToken) {
  return Rx.Observable.fromPromise(axios.get({
    url: 'https://api.spotify.com/v1/me',
  }));
}    

Rx.Observable.fromPromise(axios(config))
    .map((res) => {
        return {
            accessToken: res.data.access_token,
            refreshToken: res.data.refresh_token                
        }
    })
    .flatMap((res) => {
        return getMe(res.accessToken).map((res2) => {
          res.me = res2;
          return res;
        }
    })
    .subscribe((data) => console.log(data));

As mentioned in the above post, flatMap returns an observable. map is subsequently used to merge res with the result res2 returned from the second promise.

Also note that fromPromise is a cold observable. This means that you must have a subscription to initiate things. In your case, I presume you already have something like this:

someFunction = () => {
  return Rx.Observable.fromPromise(axios(config))
     ...
     ...
}

someFunction.subscribe((data) => console.log(data));

Solution 2

As @user3743222 pointed out, an Observable does not resolve in the sense that a Promise does. If you want the value you of the getMe method you will need to subscribe to the Observable returned by it.

return Observable.fromPromise(axios(config))
        .map(res => {
            return {
                accessToken: res.data.access_token,
                refreshToken: res.data.refresh_token                
            }
        })
        .flatMap(function(tokens) {

          //FlatMap can implicitly accept a Promise return, so I showed that here
          //for brevity
          return axios.get({url : 'https://api.spotify.com/v1/me'});
        },

        //The second method gives you both the item passed into the first function
        //paired with every item emitted from the returned Observable`
        //i.e. axios.get(...)
        function(tokens, response) {
          return {
            accessToken: tokens.accessToken,
            refreshToken: tokens.accessToken,
            //Here response is a value not an Observable
            me: response
          };
        });
Share:
19,810

Related videos on Youtube

jhamm
Author by

jhamm

I like to code. I use Java/Kotlin and js frequently.

Updated on September 15, 2022

Comments

  • jhamm
    jhamm over 1 year

    I have an Observable in which I consume another observable, but the 2nd Observable I can't get to resolve. Here is the code:

    return Observable.fromPromise(axios(config))
            .map(res => {
                return {
                    accessToken: res.data.access_token,
                    refreshToken: res.data.refresh_token                
                }
            })
            .map(res => {
                return {
                    me: getMe(res.accessToken),
                    accessToken: res.accessToken,
                    refreshToken: res.refreshToken                
                }
            })
    
    function getMe(accessToken) {
        return Observable.fromPromise(axios.get({
            url: 'https://api.spotify.com/v1/me',
        }));
    }
    

    The getMe function returns an Observable, but it is never resolved. I have tried to add a flatMap and a concat, but it still isn't resolved. How do I get the getMe to resolve?

  • user3743222
    user3743222 over 8 years
    POJO = Plain Old Javascript Object
  • jhamm
    jhamm over 8 years
    Thank you for the help, but this seems more convoluted than using Promises. There has to be a more concise way.
  • user3743222
    user3743222 over 8 years
    Sure let's see what others come up with. Question : why don't you use promises, and then convert to observable when you have the result you want? Rx.Observable.fromPromise does that, that way you have the best of both worlds.
  • user3743222
    user3743222 over 8 years
    Interesting proposition. Could be valuable to test it. In my opinion a possible problem is accessing res from the closure. I am not sure about this, but the anonymous function with res.me in its body, is executed/evaluated only when getMe emits a value, at which time I wonder if the res variable still holds its value. I code defensively around this by using only pure functions in connection with observables. So I am interested to know if I am being too cautious.
  • Jeremy
    Jeremy over 8 years
    From a closure perspective, res will still hold it's value (I have used this technique before). I do concur that it's best to having a defensive style of coding and to test thoroughly. As a side note, if there's a second Rx.Observable.fromPromise(axios(config)) execution before getMe() resolves then you'll have 2 subscribe executions. This can easily be remedied by using flatMapLatest which will ensure that you'll always get the latest getMe() response with one subscribe execution.
  • user3743222
    user3743222 over 8 years
    fair enough. Thanks for the clarification.
  • paulpdaniels
    paulpdaniels over 8 years
    Be careful in your description of fromPromise as a cold Observable. Though the value itself will be cached, making it appear as a cold Observable to all down stream subscribers. The promise itself is eager and will begin execution immediately, regardless of subscription.
  • mahatmanich
    mahatmanich about 7 years
    POJO has been taken loooong looong ago by JAVA => Plain Old Java Object. Javascript was not OOP back then ....