0

I trying to read an item (menulist) from localStorage. If it is null, I am calling a service which will store menulist after fetching it from database). It seems that service is asynchronous as I am getting Cannot read property 'sort' of null in the following code.

ngOnInit() {

    this.menulist = localStorage.getItem('menulist');
    if (!this.menulist) {
      this.SetMenuList();
    }
    this.jsonmenulist = JSON.parse(this.menulist);
    this.jsonmenulist.sort(function (a, b) { 
      return a.mnuposno > b.mnuposno;
    });
    this.jsonmenulist = this.jsonmenulist.sort();
  }

SetMenuList() {
    this._UserspecificmenuaccessService.getRMA("driver")
      .subscribe((lst) => {
        if (lst && lst.length > 0) {
          localStorage.setItem('menulist', JSON.stringify(lst));
          this.menulist = localStorage.getItem('menulist');
          console.log(this.menulist); // gets called after this.jsonmenulist.sort? 
          return true;
        }
      }, (error) => {
        console.error(error)
      });
  }

Console:

ERROR TypeError: Cannot read property 'sort' of null

[{"mnurecid":"4","mnuid":"menu1","mnuname":"Bin","mnuurl":"/bin/","mnuposno":"1.0","checked":true}, {"mnurecid":"12","mnuid":"menu9","mnuname":"Menu9","mnuurl":"/menu9","mnuposno":"9.0","checked":false}]
SamuraiJack
  • 5,131
  • 15
  • 89
  • 195
  • 3
    You can't. Possible duplicate of http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call and https://stackoverflow.com/questions/43055706/how-do-i-return-the-response-from-an-observable-http-async-call-in-angular2 . A simple way to improve this is to switch from observables to promises and use async/await in ngOnInit. – Estus Flask May 18 '18 at 06:41

3 Answers3

4

You can use toPromise() method from rxjs library to return promise rather than observable.

So In your service

getRMA(type) {
        return this.http.post(environment.baseURL + '/getmenulist', { drive: 
          type }, this.options).map((response) => response.json()
     ).toPromise().catch(e => {
    console.log(e);
    )}

    }

and In your component use async and await

 async SetMenuList() {
       let response =  await 
        this._UserspecificmenuaccessService.getRMA("driver")
          console.log(response)         
      }
S K
  • 442
  • 3
  • 5
1

Not exactly about async broblem, you just use the this.menulist before it's assigned. Just change the way you run your codes.

ngOnInit() {
    this.menulist = localStorage.getItem('menulist');
    if (this.menulist) {
        this.sortMenuList(); // Sorting the menu if we have menulist already
    } else {
        this.SetMenuList(); // Else call the service and sort the menu then
    }
}

sortMenuList() {
    this.jsonmenulist = JSON.parse(this.menulist);
    this.jsonmenulist.sort(function (a, b) { 
      return a.mnuposno > b.mnuposno;
    });
    this.jsonmenulist = this.jsonmenulist.sort();
}

SetMenuList() {
    this._UserspecificmenuaccessService.getRMA("driver")
      .subscribe((lst) => {
        if (lst && lst.length > 0) {
          localStorage.setItem('menulist', JSON.stringify(lst));
          this.menulist = localStorage.getItem('menulist');
          this.sortMenuList(); // Sorting the menu if we have menulist already
        }
      }, (error) => {
        console.error(error)
      });
  }

By the way, SetMenuList naming should be setMenuList (Just recommended for naming).

Sakata Gintoki
  • 1,817
  • 16
  • 23
0

You could write the code that need to be executed inside the subscribe function so that it is executed only after the asynchronous operation is done.

Franklin Pious
  • 3,670
  • 3
  • 26
  • 30