32

I've been building a SPA with Angular 4 on the front end and ASP.NET Core 2 on the Backend. Basically, I'm trying to automatically renew an user login, given a valid token. When I reload a page, for example, I would like that Angular stayed logged in. I'm storing the token on local storage, as well as an user object so I can check some user properties (if he/she is logged in for example).

How should I force angular to wait for the http request to finish? Here's the .net get Service:

get<T>(url: string): Observable<T> {
    let options = this.doHeaders();
    return this.doSub(this.http.get(this.doUrl(url), options));
}

private doSub<T>(obs: Observable<Response>) {
    var ob1: Observable<T> = obs.map(this.extractData)
        .catch(this.handleError);

    return ob1;
}

Here's the HTTP Request code:

   getUser() {

    if (this.storage.token == null || this.storage.token == '') {
        return;
    }
    
    this.net.get<LoginModel>(`Authentication/GetUser`).subscribe(t => {
        this.storage.token = t.token;
        this.storage.user = t.user;
        console.log(this.storage.user);
    });
}

Here's how I'm checking for the user:

export class StorageService {

    constructor(
        private storage: LocalStorageService
    ) {
    }

    public user: User = null;

    public get isLoggedIn(): boolean {
        return this.user != null;
    }

}

export class IsLoggedIn implements CanActivate {

constructor(
    private storage: StorageService,
    private router: Router
) { }

canActivate(
    childRoute: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
) {
    if (this.storage.isLoggedIn) {
        return true;
    }

    this.router.navigate(['account/login'], {
        queryParams: {
            return: state.url,
            message: 'You must be logged in'
        }
    });
    return false;
}}

The real issue is: Whenever I try to reload the page on a protected page, Angular does not wait for the http to complete, and redirects me to the login page. After about a few seconds, it logs in, but i've been redirected already. The above code is being executed on AppComponent (NgOnInit).

7
  • Normally you don't ever wait for async operations to complete in Angular. That would block the thread. You could, for example return Observable<UserModel> if you cannot get the user, then you redirect (in the subscribe) Commented Feb 8, 2018 at 23:41
  • I’m not really sure if i understood correctly. Do you mean I should take out the subscribe from the AppComponent and subscribe it wherever im checking ? Commented Feb 8, 2018 at 23:49
  • Something like that. Point is the whole app runs asynchronously using observables. I see your get user has no security, in example it's not asking for credentials. I imagine some kind of login page. Some you would do: if token is empty, go to login, subscribe to result of log in, if good continue, otherwise show login error Commented Feb 8, 2018 at 23:55
  • The getUser method will not return synchronously, you get it? Commented Feb 8, 2018 at 23:57
  • The GetUser gets the user from token (JWT). If the token is null i could redirect to login, but not all my pages are protected, so i only redirect if the user trying to access a protected route. I know Observables are async. I wouldnt care if there was any way to make a single synchronou http request. All i wanted was the application to wait for that request. Commented Feb 9, 2018 at 0:00

4 Answers 4

29

You can use promises with async/await

async getUser() {
    if (this.storage.token == null || this.storage.token == '') {
        return;
    }

    const t = await this.net.get<LoginModel>(`Authentication/GetUser`).toPromise();

    this.storage.token = t.token;
    this.storage.user = t.user;

    console.log(this.storage.user);
}

See more:

Sign up to request clarification or add additional context in comments.

6 Comments

Although this compiles and gets the user, it still doesn't solve my issue. I'm updating with a little more information, maybe i'm missing something somewhere else. Could you please have a look?
Your call return this.doSub(this.http.get(this.doUrl(url), options)); should also be changed to await the get request, maybe you need to refactor code in other places as well?
I dont know much about async, sorry for being so amateur lol. Hmm i’ll try and change the doSub. This is the only request i need to wait so maybe i’ll create a new one just for it
Please, read about httpInterceptor angular.io/guide/http#intercepting-requests-and-responses, read about switchMap and forget toPromise
@RohanAgarwal, In my opinion, concatenate Promise it's a little nightmare. Futhermore, Angular is made thinking in Observables, "await" to the response is make a sync calls, you wait until the promise resolve. For me is more natural make a call and control the response when you get the data
|
7

Use .toPromise on your observable followed by async/await.

await this.net.get<LoginModel>(`Authentication/GetUser`).toPromise();

5 Comments

Thanks for your reply, however the compiler doesnt let me do .toPromise() after subscribe or before. Maybe it's related to my net and get. I've updated the question.
import 'rxjs/add/operator/toPromise'; 🌹
Doesnt work before/after .subscribe. I have to remove subscribe in order for the compiler to accept. this.net.get<LoginModel>('Authentication/GetUser').toPromise(); Maybe did you mean: this.net.get<LoginModel>('Authentication/GetUser').toPromise().then(...);
You don't need to call subscribe, you can get t from the return value of await ...
you cannot subscribe, you can get data add "await" flag before your method.
7

Since .toPromise has been deprecated deprecations, you should use one of the two built in static conversion functions firstValueFrom or lastValueFrom.

It should be something like that

await firstValueFrom(this.net.get<LoginModel>(`Authentication/GetUser`));

Comments

-3

You can not use the async/await syntax with Observables returned by Angular HttpClient so you first need to convert the observable to a promise first.

Luckily the Observable interface exports a toPromise() method which returns a promise from the observable:

await this.net.get<LoginModel>('Authentication/GetUser').toPromise();

See this example of how to use Async/Await with Angular HttpClient

1 Comment

You added a duplicate answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.