0

Good Morning,

Even after reading about the concepts and uses of async and await, i'm still having problems with real aplicattions of them.

Basically in my ngOnInit I do a call to a function:

ngOnInit() {
    this.authenticateUser();
  }

Function that is:

authenticateUser() {

    console.log("----Autenticando Usuário----");

    this.token = localStorage.getItem("token");
    this.userName = localStorage.getItem("userName");
    this.userPhoto = localStorage.getItem("userPhoto");

    this.currentUser = this.auth.getSession(this.token);

    this.attributions = this.currentUser.sessao.grupos;
    this.userEmail = this.currentUser.sessao.email;
    this.instalation = this.currentUser.instalacao;

   }

The problem is that currentUser value returns as null in its execution, because its value was setted before the return from the promise in this.auth.getSession(this.token);

This Auth is constructed in a service called RestApiService

constructor(private auth: RestApiService) { }

Also I have inside that service the method getSession() that returns a JSONwith user informations from the API

getSession(xtrToken) {
    xtrToken = "{\"token\":\"" + xtrToken.toString() + "\"}";
    this.http.post(this.apiURL + "/auth", xtrToken)
      .subscribe(function (resposta) {
        if (resposta != null) {
          localStorage.setItem("currentUser", JSON.stringify(resposta));
          if (window.location.href.indexOf("?") > -1) {
            var url = window.location.href;
            var value = url = url.slice(0, url.indexOf('?'));
            value = value.replace('@System.Web.Configuration.WebConfigurationManager.AppSettings["BaseURL"]', '');
            var newUrl = value;
            window.history.pushState({}, null, newUrl);
          }
          this.currentUser = JSON.parse(localStorage.getItem("currentUser"));
        }
      });
      return this.currentUser;
  }

I've tried putting getSession as async, and in its call, something like this:

async authenticateUser() {

    console.log("----Autenticando Usuário----");

    this.token = localStorage.getItem("token");
    this.userName = localStorage.getItem("userName");
    this.userPhoto = localStorage.getItem("userPhoto");

    this.currentUser = await this.auth.getSession(this.token);

    this.attributions = this.currentUser.sessao.grupos;
    this.userEmail = this.currentUser.sessao.email;
    this.instalation = this.currentUser.instalacao;

   }

But it didn't make any difference.

So, is there a way to wait the result from the API before I set the value in this.currentUser ?

3 Answers3

0

Although your getSession method tries to perform an asynchronous action, you haven't set it up to do so properly. You're returning currentUser outside of the subscribe block, and the whole method has no way of telling its caller that it is asynchronous, so async/await won't make a difference.

When it comes to async methods, you have a few choices. In Angular, we generally use Observables as they allow the most control. In this case, you could simply return the http.post Observable in getSession, and then subscribe to it in authenticateUser. Then you can either put the following lines inside the subscribe call or use pipe and RxJS operators to perform the next actions.

You could also have getSession return a Promise which resolves with the required data. That would allow async/await to work (although it's not an Angular pattern).

Will Alexander
  • 3,425
  • 1
  • 10
  • 17
  • When I try to subscribe to it at the `authenticateUser` it only appears to unsubscribe, do you know why would that happen? – Gustavobezerra Aug 15 '19 at 14:49
  • Because you're returning the `Subscription` because you've left the `subscribe` call in `getSession` Like I said, you take the `subscribe` call out of `getSession` and place it in `authenticateUser`. – Will Alexander Aug 15 '19 at 14:50
0

getSession() must return a promise in order for await to work in this case.

return this.http.post(this.apiURL + "/auth", xtrToken)
    .toPromise()
    .then(res => res.json())
    .catch(err => console.error(err));

or

getSession(){
    return new Promise((resolve, reject) => {
        ...
        resolve(data)
    })
}
Chris
  • 1,829
  • 1
  • 15
  • 22
0

You can pipe with map from rxjs to your return value and set to JSON. Promise and Observable are slight different even though both are asynchronous operation. When you use observable pattern and it stared listening to it when you subscribe which means you may receive multiple values later (async). Promise pattern gives you back one value later which you will listen to from resolve(result).

login(model: AccessUser) {
    return this.http.post(this.endpoint, model).pipe(
      map((response: AccessToken) => {
        const user = response;
        if (user) {
          localStorage.setItem('token', user.token);
          localStorage.setItem('user', JSON.stringify(user.user));
          this.decodedToken = this.jwtHelper.decodeToken(user.token);
          this.currentUser = user.user;
        }
      })
    );
  }

So in your case,

getSession(xtrToken) {
    xtrToken = "{\"token\":\"" + xtrToken.toString() + "\"}";
    this.http.post(this.apiURL + "/auth", xtrToken)
      .map((resposta) => {
        if (resposta != null) {
          localStorage.setItem("currentUser", JSON.stringify(resposta));
          if (window.location.href.indexOf("?") > -1) {
            var url = window.location.href;
            var value = url = url.slice(0, url.indexOf('?'));
            value = value.replace('@System.Web.Configuration.WebConfigurationManager.AppSettings["BaseURL"]', '');
            var newUrl = value;
            window.history.pushState({}, null, newUrl);
          }
          this.currentUser = JSON.parse(localStorage.getItem("currentUser"));
        }
      });
      return this.currentUser;
  }

authenticateUser() {

    console.log("----Autenticando Usuário----");

    this.token = localStorage.getItem("token");
    this.userName = localStorage.getItem("userName");
    this.userPhoto = localStorage.getItem("userPhoto");

    this.auth.getSession(this.token).subscribe((result) => {
    this.currentUser = result;
    });

    this.attributions = this.currentUser.sessao.grupos;
    this.userEmail = this.currentUser.sessao.email;
    this.instalation = this.currentUser.instalacao;

   }
phonemyatt
  • 1,287
  • 17
  • 35
  • put the lineas of this.attributions=this.currentUser,this.userEmail.. INSIDE subscribe function – Eliseo Aug 15 '19 at 19:54