0

So I have an observable which makes an HTTP post to get the access token from a server. I have another which performs a get to the same server, but requires the access token from the first to exist. So I would like to be able to subscribe to both observables at the same time in two different places, but the GET observable must of course wait on the POST observable. How can I make an observable wait on another Observables subscribe completion?

Oleksii Pavlenko
  • 1,327
  • 1
  • 11
  • 25
Colton Voege
  • 409
  • 2
  • 5
  • 12

2 Answers2

0

Not sure I understand right but here follows an option. Assuming postHttp$ is your access token fetch observable, and getFromServer$ the one performing the get to the server, and assuming those are sequences of only one value (i.e. promise-like):

  • postHttp$.flatMap(function (authToken){return $.ajax(...)}) will wait for postHttp to have a value to produce a promise which will be flattened down to its resolved value. i.e. the GET observable (...) wait on the POST observable. To retrieve the value, you can subscribe to the observable, or continue chaining other operators to it.
    • flatMap accepts promises as the return value of its selector function parameter, so no need here to convert to Rx.Observable.

Is that what you wanted?

user3743222
  • 18,345
  • 5
  • 69
  • 75
-1

I figured out a solution so I thought I'd go ahead and post my own answer. If anyone knows a more efficient way of doing things definitely post an answer and I'll accept it!

this.getObservable = Rx.Observable.create(function(observer){
  this.postObservable.subscribe(null, null, function onComplete(){
    var ajaxObservable = Rx.Observable.fromPromise($.ajax({
      url: this.apiPath,
      method: 'GET',
      beforeSend: function (xhr) {
        // this.authToken is created by the postObservable, so we have to subscribe to the oncomplete of that in order to use it.  
        xhr.setRequestHeader('Authorization', this.authToken); 
      }.bind(this)
    }).promise());
    ajaxObservable.subscribe(
      function onNext(data){
        observer.next(data);
      }, 
      function onError(error){
        observer.error(error);
      }, 
      function onComplete(){
        observer.complete();
      }
    );
  }.bind(this));
}.bind(this));

In this code, getObservable subscribes to postObservable, and only once that completes does it make it's own Ajax call. This is useful because it lets my pages immediately subscribe to whatever GET observable they want, and not have to worry about the callback hell of subscribing first to the postObservable, then subsribing to the next observable when that's ready. To the individual page, the post request is completely hidden, they just subscribe to the get request.

Note that this code would probably be a lot cleaner with arrow functions but I'm trying to stay compliant with some older browsers.

Colton Voege
  • 409
  • 2
  • 5
  • 12
  • the important thing is that it works for you. However: 1. If you have to chain a sequence of observables any longer than this one, it won't be callback hell, but it will be hell anyways, 2. those mechanisms (sequencing of operations) are already implemented in the Rx operators, best is to reuse and compose existing code, which is extensively tested. 3. Generally speaking, it is better to program functionally, i.e. using pure functions (no side effects) as much as possible, this simplify your reasoning and also your testing (I understand here that `postObservable` somehow modify `authToken`) – user3743222 Jan 06 '16 at 19:58
  • you are really just doing `this.postObservable.flatMap(function (authToken){return $.ajax(...)})`. Then you can subscribe to that to process the data from the ajax call. I will update my answer to reflect the new information. I do recommend you to read this to further your understanding of Rxjs : https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 – user3743222 Jan 06 '16 at 20:05
  • @user3743222 Interesting. Do you think you could update your answer to reflect this comment? If you can put it in terms of the variables I gave above, I'd be glad to accept your answer. – Colton Voege Jan 06 '16 at 20:56