15

I'm still confused about how rxjs works.

I am building an Ionic app that makes a request to my server and expects json. I have successfully been able to subscribe to an http.post and get the data I need.

However now my problem is that I need to pass an auth token in the http request which I get from Storage. This is an issue because I need to wait until Storage is ready and I get my token value from it before I call the http.post request.

This is where I am trying to get my json data

getPlanograms() {

    //API URL
    let requestURL = 'https://myapiurlhere';
    let headers = new Headers({'Content-Type': 'application/json'});

    return this.storage.ready().then(() => {

        return this.storage.get('id_token').then((val) => {

            headers.append('Authorization', 'Bearer ' + this.authCredentials.token);
            let options = new RequestOptions({headers: headers});
            return this.http.post(requestURL, {}, options)
                .map(response => <Planogram[]>response.json());

        })
    });
}

Which gets called from here

 ionViewDidLoad (){
    this.merchandisingDataService.getPlanograms()
        .subscribe(Planogram => this.planograms = Planogram);
}

However, when I try to do this I get the following error

Property 'subscribe' does not exist on type 'Promise'.

What would be the best way to achieve my objective?

0xcaff
  • 13,085
  • 5
  • 47
  • 55
dr_ermio
  • 811
  • 1
  • 10
  • 21
  • 7
    `getPlanograms()` returns a `Promise`. You can't `subscribe` to promises. You can `then` promises and `subscribe` to observables. – 0xcaff May 14 '17 at 17:52
  • Thanks for your comment. What would be the best way to keep returning the observable from the http.post request while still executing it only after my token variable has been retrieved from Storage? – dr_ermio May 14 '17 at 18:00

3 Answers3

19

You could consume with .then() by changing:

ionViewDidLoad () {
    this.merchandisingDataService.getPlanograms()
        .then(Planogram => this.planograms = Planogram);
}

Or, you could make getPlanograms return an Observable.

getPlanograms() {   

    // API URL
    let requestURL = 'https://myapiurlhere';
    let headers = new Headers({'Content-Type': 'application/json'});

    // this converts from promise to observable
    return Observable.fromPromise(this.storage.ready()
        .then(() => this.storage.get('id_token'))
        .then((val) => {
            headers.append('Authorization', 'Bearer ' + this.authCredentials.token);
            let options = new RequestOptions({headers: headers});

            return this.http.post(requestURL, {}, options)

                // map converts from observable to promise
                // (returned by response.json())
                .map(response => <Planogram[]>response.json());
        });
    }));
}

Now you can consume with .subscribe() as you did in the question.

0xcaff
  • 13,085
  • 5
  • 47
  • 55
2

Following caffinatedmonkey's suggestion, I ended up with this working function:

    getPlanograms() {

    //API URL
    let requestURL = 'https://myapiurlhere';

    return Observable
        .fromPromise(this.storage.get('id_token'))
        .flatMap(token =>{
            let headers = new Headers({'Content-Type': 'application/json'});
            headers.append('Authorization', 'Bearer ' + token);
            let options = new RequestOptions({headers: headers});
            return this.http.get(requestURL, options)
                .map(response => <Planogram[]>response.json())
                .catch(this.handleError);
        }
    );
}
dr_ermio
  • 811
  • 1
  • 10
  • 21
0

The 2020 / 2021 version of this answer is as follows, RequestOptions is deprecated, Observable.fromPromise is now simple from and flatMap is now mergeMap and you have to pipe to the mergeMap:

Dependencies / imports:

import { Observable, throwError, of, from } from 'rxjs';
import { map, catchError, mergeMap } from 'rxjs/operators';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';

Function:

listProducts(){
return from(this.storage.get('token'))
  .pipe(mergeMap(token =>{
      const headers = new HttpHeaders().append('Content-Type', 'application/json').append('Authorization', 'Bearer ' + token);
      return this.http.get(`${url}`, { headers: headers })
  }
));
}
Grant
  • 5,709
  • 2
  • 38
  • 50