Reputation: 7567
I am working on a personal Angular project. Still trying to learn and move from AngularJS to Angular :)
This is my code:
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { LoginService } from './login.service';
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(
private _router: Router,
private _loginService: LoginService
) {
}
isLoggedIn() {
let token = localStorage.getItem('token');
if ( token ) {
this._loginService.isLoggedIn(token)
.subscribe(v => {
return v.status == 'ok';
});
} else {
return false;
}
};
canActivate() {
console.log(this.isLoggedIn());
if (this.isLoggedIn()) {
return true;
} else {
this._router.navigate(['/login']);
return false;
};
}
}
However my problem is:
this.
on the console.log(this.isLoggedIn());
then "undefined" is printed out.[ts] Cannot find name 'isLoggedIn'. Did you mean the instance member 'this.isLoggedIn'?
and the same on console Uncaught (in promise): ReferenceError: isLoggedIn is not defined
isLoggedIn()
is used without a problem from other files where I call it.Upvotes: 3
Views: 2508
Reputation: 8911
The reason you are getting undefined on the method:
isLoggedIn() {
let token = localStorage.getItem('token');
if ( token ) {
this._loginService.isLoggedIn(token)
.subscribe(v => {
return v.status == 'ok';
});
} else {
return false;
}
};
Is because the Subscription this._loginService.isLoggedIn(token)
is asynchronous and does not return immediately. So the method isLoggedIn()
finishes executing and returns before there is a response.
What you could do instead and what I do is the have your _loginService
maintain a local variable that other components can read and consume or a function that can synchronously check the token to make sure it's valid. If a token exists, then a user has logged in, and what you can do from there is check the token to make sure it hasn't expired. That could be done a couple different ways. If your using the angular2-jwt
library to help handle your JWT token you could have a method in your _loginService
that looks something like this:
authenticated() {
// Check if there's an unexpired JWT
return tokenNotExpired();
}
If you aren't using the angular-jwt
library to help manage the JWT token, you could do something like this:
isTokenValid(){
let token = localStorage.getItem('token');
let decodedToken = window.atob(token.split('.')[1]);
if((decodedToken.exp * 1000) < Date.now()){
return false;
}
return true;
}
Hope that helps.
Upvotes: 2
Reputation: 424
This may not qualify as an answer but I do not have enough reputation points to post a comment - so everyone, pardon me :)
I think you cannot return a value from subscribe like that as it is an async call..
Instead, your isLoggedIn() method should be returned as shown below:
isLoggedIn() {
let token = localStorage.getItem('token');
if ( token ) {
return this._loginService.isLoggedIn(token)
.subscribe(v => {
return v.status == 'ok';
});
} else {
return false;
}
};
Note the change is here: return this._loginService.isLoggedIn(token)...
Hope this helps.
EDIT: Ignore my answer above... That would still not work :( sorry... What's happening is, you are calling isLoggedIn() which executes an asynchronous call (ie a call that will continue executing in the background and return later). That is why you are getting an 'undefined'. What I would do is follow Tyler's advice above and have a local variable in which you store the returned value in and utilize later OR you could pass in a callback to isLoggedIn() method - this callback will be invoked once the async call is done. See below:
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { LoginService } from './login.service';
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(
private _router: Router,
private _loginService: LoginService
) {
}
isLoggedIn(callback: (v) => void) {
let token = localStorage.getItem('token');
if ( token ) {
this._loginService.isLoggedIn(token)
.subscribe(v => {
callback(v)
});
}
};
canActivate() {
this.isLoggedIn((v) => { // this here is your callback function which will get invoked once async call is done
if(v.status == 'ok' {
// do something...
return true;
} else {
// do something
this._router.navigate(['/login']);
}
});
}
}
Upvotes: 1