2
votes

I need to wait for a promise to complete before activating an observable in Angular 2 with RxJS.

More specifically, I need to set up state using a third party library that returns promises, and insert some resulting information into my HTTP headers before making GET requests:

export class LiveDataService {

    private headersPromise;

    constructor(public http: Http) {
        this.headersPromise = $.connection('/init').then((state) => setupHeaders(state));
    }

    activate(route: string) {
        return this.http.get('api/v1/' + route, { headers })
            .Merge(anotherStateBasedObservable);
    }

)

Except, although I need to return the observable immediately as shown, I also must wait for the promise to complete before calling the http.get.

I can think of a couple ways that require like 3-4 stages of translation, but I feel like there should be a fairly direct way to do this.

1

1 Answers

6
votes

Do you really need an observable to be returned? I would do something like this:

// getState caches the state promise, so '/init' gets requested only once
// but is lazy loaded
var _statePromise = null;
function getState() {
  return _statePromise || (_statePromise = $.connection('/init'));
}

function routeChange(route) {
  return getState()
    .then(state => setupHeaders(state))
    .then(headers => this.http.get('api/v1/' + route, { headers }));
}

EDIT

You can map an observable with async functions using flatMap or flatMapLatest:

// routeSource is an RxJS Observable
var contentSource = routeSource.flatMapLatest(routeChange);

EDIT

You can convert promises to observables and vica versa: Bridging Promises

This might be what you need:

// getState caches the state promise, so '/init' gets requested
// only once, but is lazy loaded
var _statePromise = null;
function getState() {
  return _statePromise || (_statePromise = $.connection('/init'));
}
function Method(route) {
  return Rx.Observable.fromPromise(this.getState())
    .flatMap(state => setupHeaders(state)) // flatMap handles promises
    .flatMap(headers => this.http.get('api/v1/' + route, { headers }))
    .merge(anotherStateBasedObservable);
}