2

I've put an angular routing authguard to put my page. I've an api that checks if the token is valid and based on that I want to return true or false for further navigation.

But seems that in 'subscribe' I assign my 'result' flag true not persisting outside of the subscribe. Is 'result' variable in wrong scope here? How can I correct that? Please help me understand my mistake in below code.

canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
  const jwt = localStorage.getItem('jwt');
  let result = false;

  this.signinService.isSignedin(jwt).subscribe((res) => { // <---
    console.log(res.json().message);
    if (res.json().message === 'Token Valid') {
      result = true;
      console.log(result);
      return true;
    } else {
      result = false;
      return false;
    }
  }, (err) => { // <---
    console.log(err);
    result = false;
    return false;
  });
  console.log('END' + result);
  return result;}

The above code prints out on console in below order, which seems to be weird to me. Anyone can explain please?

ENDfalse

Token Valid

true

4

3 回答 3

1

The result value is returned before the callback function you defined is executed. Which is quite logical because the callback is called after the api round trip has finished.

于 2017-12-21T21:20:56.137 回答
1

But seems that in 'subscribe' I assign my 'result' flag true not persisting outside of the subscribe.

I think you are not fully understanding how the interpreter will read and evaluate this code. Because the JavaScript event loop is never blocking, the interpreter will get to the subscribe block, make the request, and then continue along executing the code outside of the subscribe block without waiting for the response to come back. This is why "ENDfalse" is printed first. Then the response comes in and the callback function is executed with the line console.log(res.json().message); printing "Token Valid" and console.log(result); returning true.

One way you could fix this might be to return the whole observable and then subscribe to in the place where you actually want to use the value of "result" (and in fact your function signature of canActivate shows that you should be returning an observable, not the data).

canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
  const jwt = localStorage.getItem('jwt');
  return this.signinService.isSignedin(jwt);
}
于 2017-12-21T21:24:32.980 回答
-1

You cannot return anything from subscribe, but what you can do, is to return an Observable from your guard.

Also as pointed out by the others, this is asynchronous, therefore the order of the console logs. You can read more about it here: How do I return the response from an Observable/http/async call in angular2?

As for how to format your code, let's as mentioned return an Observable:

// add 'return' and use 'map' instead: 
return this.signinService.isSignedin(jwt).map((res) => {
  if (res.json().message === 'Token Valid') {
    return true;
  } else {
    return false;
  }
}, (err) => {
  return false;
});
于 2017-12-22T08:50:50.887 回答