0

I need to return Observable from promise, however I am bogged down by the syntax as I am trying to learn angular.So here is the thing:

I have a following function getCountries(this is subscribed by another utility) where I need to make a call to retrieve countries list.'lang' is not defined yet.I added that just to complete the url of my api.

getCountries(): Observable<Country[]> {
    if (this.countries) {
       return Observable.of(this.countries);
    } else if (this.countriesObservable) {
      return this.countriesObservable;
    } else {
//lang is not defined yet it has to be retrieved from storage

      this.countriesObservable = this.http.get(AppSettings.API_URL + '?locale=' + lang).map(json => {
        delete this.countriesObservable; // when the cached countries is available we don't need  reference anymore
        this.countries = json as Country[];
        this.countries = this.countries.sort(function (a, b) { return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0); });
        return this.countries;
      }).share();
      return this.countriesObservable;
    }
  }

Since api requires language(lang) and this info is stored in storage which can be retrieved from storage as follows:

  this.storage.get(AppSettings.STORAGE_KEYS.LANGUAGE_APP).then(language=>{
        //here I can use language
      });

Now the place where I am stuck is how to make a call to to my api after I retrieve language info from the above promise. I need to make sure that the function(getCountries) still returns the observable it was returning originally. Thanks for your help.

Some people suggested to wrap them in Observable.fromPromise, I did the same , however this broke the code.I must be missing something I know.Here it is:Did it miss to return something, Posting my stack trace after the code:

 getCountries(): Observable<Country[]> {
    if (this.countries) {
       return Observable.of(this.countries);
    } else if (this.countriesObservable) {
      return this.countriesObservable;
    } else {
      Observable.fromPromise(this.storage.get(AppSettings.STORAGE_KEYS.LANGUAGE_APP)).subscribe(language=>{
        //here I can use language
        this.countriesObservable = this.http.get(AppSettings.API_URL + '?locale=' + language).map(json => {
          delete this.countriesObservable; 
          this.countries = json as Country[];
          this.countries = this.countries.sort(function (a, b) { return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0); });
          return this.countries;
        }).share();
        return this.countriesObservable;
      });
    }
  }



Error: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
    at http://localhost:8100/build/main.js:71:33
    at new t (http://localhost:8100/build/polyfills.js:3:20886)
    at UtilsProvider.webpackJsonp.10.UtilsProvider.getCountryById (http://localhost:8100/build/main.js:70:16)
    at MyApp.webpackJsonp.851.MyApp.updateUserInfo (http://localhost:8100/build/main.js:10067:47)
    at http://localhost:8100/build/main.js:9774:23
    at SafeSubscriber.schedulerFn [as _next] (http://localhost:8100/build/vendor.js:4004:36)
    at SafeSubscriber.__tryOrUnsub (http://localhost:8100/build/vendor.js:16987:16)
    at SafeSubscriber.next (http://localhost:8100/build/vendor.js:16934:22)
    at Subscriber._next (http://localhost:8100/build/vendor.js:16874:26)
    at Subscriber.next (http://localhost:8100/build/vendor.js:16838:18)
    at c (http://localhost:8100/build/polyfills.js:3:19132)
    at c (http://localhost:8100/build/polyfills.js:3:18841)
    at http://localhost:8100/build/polyfills.js:3:19613
    at t.invokeTask (http://localhost:8100/build/polyfills.js:3:15040)
    at Object.onInvokeTask (http://localhost:8100/build/vendor.js:4238:33)
    at t.invokeTask (http://localhost:8100/build/polyfills.js:3:14961)
    at r.runTask (http://localhost:8100/build/polyfills.js:3:10214)
    at o (http://localhost:8100/build/polyfills.js:3:7274)
    at e.invokeTask [as invoke] (http://localhost:8100/build/polyfills.js:3:16203)
    at p (http://localhost:8100/build/polyfills.js:2:26993)
Kumar
  • 267
  • 2
  • 4
  • 17
  • 1
    Possible duplicate of [Convert promise to observable](https://stackoverflow.com/questions/39319279/convert-promise-to-observable) – bugs Apr 24 '18 at 17:06
  • Do you even need to do this - this.storage.get(AppSettings.STORAGE_KEYS.LANGUAGE_APP).then(language=>{ //here I can use language }); Can't you just do this.storage.get(AppSettings.STORAGE_KEYS.LANGUAGE_APP)? –  Apr 24 '18 at 17:40

2 Answers2

1

Any Promise can be (easily) turned to an Observable with : Observable.fromPromise()

Observable.fromPromise(this.storage.get(AppSettings.STORAGE_KEYS.LANGUAGE_APP))
.subscribe((language) => {
    //here you can use language
});
Pac0
  • 21,465
  • 8
  • 65
  • 74
1

Just use Observable.fromPromise. So in your case, it would be

getCountries(): Observable<Country[]> {
    if (this.countries) {
       return Observable.of(this.countries);
    } else if (this.countriesObservable) {
      return this.countriesObservable;
    } else {
      return Observable.fromPromise(this.storage.get(AppSettings.STORAGE_KEYS.LANGUAGE_APP)).mergeMap(language=>{
        //here I can use language
        this.countriesObservable = this.http.get(AppSettings.API_URL + '?locale=' + language).map(json => {
          delete this.countriesObservable; // when the cached countries is available we don't need the  reference anymore
          this.countries = json as Country[];
          this.countries = this.countries.sort(function (a, b) { return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0); });
          return this.countries;
        }).share();
        return this.countriesObservable;
      });
    }
  }
  • so you mean to change my function like this, adding it to my question details as I cannot add it in comment. – Kumar Apr 24 '18 at 17:22
  • I added the details in my post.Thanks – Kumar Apr 24 '18 at 17:29
  • Thanks for the tip, however my code is still broken I have added details in question.Any clue why I get that error? – Kumar Apr 24 '18 at 17:36
  • Look at the link here ->https://www.js-tutorials.com/javascript-tutorial/use-localstorage-sessionstorage-using-webstorage-angular4/. If you are getting the data from local Storage why does it have to be async, i.e. Promise? –  Apr 24 '18 at 17:37
  • Yes it is promise. The definition is like this in the library: Storage.prototype.get = function (key) { return this._dbPromise.then(function (db) { return db.getItem(key); }); }; – Kumar Apr 24 '18 at 17:57
  • Updated the answer. –  Apr 24 '18 at 18:59
  • Basically the mergemap operator allows for multiple subscriptions. More here -> https://www.learnrxjs.io/operators/transformation/mergemap.html –  Apr 24 '18 at 19:08