0

if I have the following implementation of CanActivate in an AuthGuard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
  let token = localStorage.getItem('token');
  if (token) {
    this.authService.userInfo(token, (err, result) => {
        if (err) return false;
        return true;
    }
  }
  return false;
}

Will the guard wait until the callback function executes, knowing that userInfo below actually uses HTTP to call Auth0.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Sammy
  • 3,395
  • 7
  • 49
  • 95

1 Answers1

0

Note that the return signature of CanActivate's canActivate method is:

Observable<boolean>|Promise<boolean>|boolean

so it can deal with an asynchronous response.

However, that's not what you're giving it; if there is a token you return a boolean, but if there isn't you return nothing at all; the return inside the callback doesn't alter what's returned from canActivate at all. So, as currently written, the guard will not wait for the response from the service.

If you control the service you should refactor it to use observables rather than taking a callback, as that fits much more naturally into the RxJS-based Angular world. If not, you will need to convert the callback to a promise or observable; see e.g. Making an Observable from a callback, or fromCallback. For consistency, you should also return Observable.of(false) in the other case.

Community
  • 1
  • 1
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Sorry, there's an `else` missing up there, since I was just writing the code for demonstration purposes... but I guess that would not change your answer? – Sammy May 19 '17 at 12:30
  • @Sammy well without the `else` it will always return false, but still: no waiting, unless you return something it can wait fort. – jonrsharpe May 19 '17 at 12:34
  • Alright so what you're saying is if I return an observable of a boolean it will simply wait for it to emit something first. That's ok! But then again, may you tell me why on several other threads I've been reading that I should use the `.first()` operator? I don't get that! – Sammy May 19 '17 at 12:36
  • 1
    You mean `Observable.first`? That just means you only return the *next* value emitted by the observable, then it completes, so if other values appear in the future they aren't included. I'd recommend some time looking into reactive streams/RxJS; once you get the hang of it things feel much more natural. I wrote a blog article on some of the stuff my team is doing with it: http://blog.jonrshar.pe/2017/Apr/09/async-angular-data.html – jonrsharpe May 19 '17 at 12:46