Angular 2中的方法是未定义的或不可调用的

时间:2017-03-06 12:57:27

标签: angular

我正在开展个人Angular项目。仍在尝试学习并从AngularJS转移到Angular:)

这是我的代码:

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;
        };
    }

}

但我的问题是:

  1. 如果我将this.保留在console.log(this.isLoggedIn());上,那么"未定义"打印出来。
  2. 如果我删除它,那么我在VS代码[ts] Cannot find name 'isLoggedIn'. Did you mean the instance member 'this.isLoggedIn'?上有以下消息,并在控制台上Uncaught (in promise): ReferenceError: isLoggedIn is not defined
  3. 方法isLoggedIn()在我调用的其他文件中使用没有问题。

2 个答案:

答案 0 :(得分:2)

您在方法上未定义的原因:

isLoggedIn() {
    let token = localStorage.getItem('token');
    if ( token ) {
        this._loginService.isLoggedIn(token)
              .subscribe(v => {
                   return v.status == 'ok';
         });
     } else {
           return false;
      }
};

是因为订阅this._loginService.isLoggedIn(token)是异步的,并且不会立即返回。所以方法isLoggedIn()完成执行并在有响应之前返回。

你可以做什么而我做的是让你的_loginService维护一个其他组件可以读取和使用的局部变量,或者一个可以同步检查令牌以确保它有效的功能。如果存在令牌,则用户已登录,您可以从中执行的操作是检查令牌以确保其未过期。这可以通过几种不同的方式完成。如果您使用angular2-jwt库来帮助处理您的JWT令牌,那么_loginService中的方法可能会如下所示:

authenticated() {
    // Check if there's an unexpired JWT
    return tokenNotExpired();
}

如果您没有使用angular-jwt库来帮助管理JWT令牌,您可以这样做:

isTokenValid(){
    let token = localStorage.getItem('token');
    let decodedToken = window.atob(token.split('.')[1]);

    if((decodedToken.exp * 1000) < Date.now()){
       return false;
    }
    return true;
}

希望有所帮助。

答案 1 :(得分:1)

这可能没有资格作为答案,但我没有足够的声誉点发表评论 - 所以大家,请原谅我:)

我认为你无法从订阅中返回一个值,因为它是异步调用..

相反,应返回isLoggedIn()方法,如下所示:

isLoggedIn() {
            let token = localStorage.getItem('token');
            if ( token ) {
                return this._loginService.isLoggedIn(token)
                    .subscribe(v => {
                        return v.status == 'ok';
                    });
            } else {
                return false;
            }
        };

请注意,此处的更改是:return this._loginService.isLoggedIn(token)...希望这会有所帮助。

编辑: 忽略我上面的答案......那仍然行不通:(对不起...... 发生了什么,你正在调用isLoggedIn()来执行异步调用(即一个将在后台继续执行并稍后返回的调用)。这就是为什么你得到一个未定义的&#39;。我要做的是遵循上面的Tyler建议,并有一个局部变量,在其中存储返回的值并在以后使用或者你可以将回调传递给isLoggedIn()方法 - 这个回调将在异步时被调用通话已完成。见下文:

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']);
            }
        });
    }

}