角度控制器函数一旦 $q.defer() 完成



我是角度的新手,可能完全错了。 在/sites 控制器页面上,我想访问 verifyAuth.getUserSiteAccess() 以返回站点列表并为视图构建 html 链接。

我正在使用谷歌身份验证模块,如果用户登录userSites var为空,所以我ping谷歌,然后调用/api/index.php/login返回用户站点列表,那么在这种情况下以$q.defer().resolve(true)完成; 问题是站点控制器函数在定义之前尝试访问 userSites。 有没有办法在 $q.defer().resolve 完成后调用 $scope.test()? 还是有更好的方法可以做到这一点?

如果我运行 setTimeout($scope.test, 500),它可以正常工作。

路由 -> 验证用户访问令牌,如果未定义,则加载用户网站 ->验证区域访问权限 ->完全延迟。

站点控制器

'use strict';
angular.module('mps.sites', ['ngRoute'])
.controller('sites', ['verifyAuth', '$rootScope', '$scope', '$q', function(verifyAuth, $rootScope, $scope, $q) {
    $scope.test = function() {
      var test = verifyAuth.getUserSiteAccess();
      console.log('test', test, '/test');
    };
    $scope.test();
}]);

** 应用程序.js路由和身份验证 ** - 不是整个文件...

'use strict';
angular.module('mps', [
  'ngRoute',
  'angularOauth',
  'googleOauth',
  'mps.global',
  'mps.home',
  'mps.sites',
  'mps.site'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/', {
    templateUrl: 'views/home/index.html',
    controller: 'home',
    resolve: {
      auth: function(verifyAuth) {
        verifyAuth.verifyUserAccess(true);
      }
    }
  });
  $routeProvider.when('/sites', {
    templateUrl: 'views/sites/index.html',
    controller: 'sites',
    resolve: {
      auth: function(verifyAuth) {
        console.log('sites route selected');
        verifyAuth.verifyUserAccess(false);
      }
    }
  });

.factory('verifyAuth', ['$rootScope', '$window', '$q', '$location', '$timeout', '$http', 'Token', 
function($rootScope, $window, $q, $location, $timeout, $http, Token) {
  var userSites = null;
  return {
    deferLocation: function(isToken, index) {
      var deferred = $q.defer();
      var _location = $location;
      if(isToken) {
        switch(index) {
          case true:
            // Homepage/site toggling.
            deferred.reject();
            _location.path('/sites');
            _location.replace();
            break;
          default:
            // All pages.
            deferred.resolve(true);
            break;
        }
      } else {
        // No token, redirect to login screen.
        this.userError();
      }
    },
    verifySectionAccess: function(userSites, siteName, index) {
      if(siteName) {
        // Subpage, verify section.
        for(var i in userSites.sites) {
          if(userSites.sites[i].sitename === siteName) {
            this.deferLocation(true, index);
            return false;
          }
        }
      } else {
        // Sites page.
        this.deferLocation(true, index);
        return false;
      }
      // No access to section.
      this.userError();
      return false;
    },
    // Check user permission are set.
    verifyUserAccess: function (index, siteName) {
      var token = Token.get();
      var _this = this;
      if(token) {
        if(userSites) {
          // Verify user section access.
          _this.verifySectionAccess(userSites, siteName, index);
        } else {
          // Use google token to get user email and load site permissions.
          Token.verifyAsync(token).
            then(function(data) {
              $http({method: 'GET', async: false, url: '/api/index.php/login/' + data.email}).success(function(d) {
                userSites = d;
                // Verify user access to specific section.
                _this.verifySectionAccess(userSites, siteName, index);
              });
            }, function(error) {
              _this.userError();
              return false;
            }
          );
        }
      } else {
        this.deferLocation(false, index);
      }
    },
    getUserSiteAccess: function() {
      console.log(userSites);
      return userSites;
    }

你在这里有很多问题,似乎都源于对承诺如何运作的误解:

1) 进行异步操作且.then能够返回承诺的函数。在您的情况下,您的deferLocation会创建一个承诺(尽管不会返回它),但它甚至不会异步执行任何操作。另一方面,唯一做异步(verifyUserAccess)的函数根本没有承诺。

2)如果您希望使用异步值解析resolve参数(就像auth一样),则该函数需要返回一个承诺。然后$route将等到承诺得到解决。在您的情况下,您不会返回任何东西。

我建议你多读一些关于承诺的信息。通过模拟$timeout通话构建一些小东西,并在遇到问题时提出具体问题。

下面是有关如何构建它的高级想法:

app.factory("verifyAuth", function($q, Token, AuthSvc, SitesSvc) {
  return {
    verifyUserAccess: function(site){
      var deferred = $q.defer();
      var token = Token.token;
      if (!token){
        deferred.reject("no-token");
      } else {
        AuthSvc.verifyToken(token)
          .then(function(result){
            if (result.isValid){
              // returns a promise to get a list of userSites
              return SitesSvc.getSites(result.user);
            } else {
              return deferred.reject("token-not-valid");
            }
          })
          .then(function(userSites){
            if (checkAccessPermissions(site, userSites)){
              deferred.resolve(true);
            } else {
              deferred.resolve(false);
            }
          })
          .catch(function(error){
            // some other error
            deferred.reject(error);
          });
      }
      return deferred.promise;
    }
  };
});

路由器调用返回 verifyUser.buildUserData 在解析中,这将检查是否有令牌,如果没有将用户注销。 然后检查是否存在站点列表全局变量,如果没有,则将令牌ping到google以获取用户电子邮件,并将用户电子邮件发送到数据库以获取站点列表,从那里循环访问列表并检查身份验证是否将站点名称传递到buildUserData。

下面的示例将在呈现视图之前处理所有身份验证。 感谢新开发人员为我指出正确的方向。

路由器:

config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/', {
    templateUrl: 'views/home/index.html',
    controller: 'home',
    resolve: {
      auth: function(verifyUser) {
        return verifyUser.homepageRedirect();
      }
    }
  });
  $routeProvider.when('/sites', {
    templateUrl: 'views/sites/index.html',
    controller: 'sites',
    resolve: {
      auth: function(verifyUser) {
        return verifyUser.buildUserData();
      }
    }
  });
 $routeProvider.when('/sites/:site/scheduling', {
    templateUrl: 'views/sites/scheduling/index.html',
    controller: 'site',
    resolve: {
      auth: function(verifyUser, $route) {
        return verifyUser.buildUserData($route.current.params.site);
      }
    }
  });

工厂

.factory('getUserEmail', ['$rootScope', '$window', '$q', '$location', '$timeout', '$http', 'Token', function($rootScope, $window, $q, $location, $timeout, $http, Token) {
  return {
    // Get user email address based on token.
    getEmail: function() {
      var deferred = $q.defer();
      var token = Token.get();
     $http({method: 'GET', async: false, url: 'https://www.googleapis.com/oauth2/v1/tokeninfo', params: {access_token: token }}).
       success(function(data) {
         $rootScope.username = data.email;
         deferred.resolve(data);
         return data;
       }).error(function(data) {
         deferred.reject(data);
       });
      return deferred.promise;
    }
  }
}])
.factory('getUserSites', ['$rootScope', '$window', '$q', '$location', '$timeout', '$http', 'Token', function($rootScope, $window, $q, $location, $timeout, $http, Token) {
  return {
    // Get user site access.
    getSites: function() {
      var deferred = $q.defer();
      console.log('site list is undefined.');
      $http({method: 'GET', async: false, url: '/api/index.php/login/' + $rootScope.username}).
        success(function(data) {
          $rootScope.sites = data.sites;
          deferred.resolve(data);
        }).error(function(data) {
          deferred.reject(data);
        });
      return deferred.promise;
    }
  }
}])
.factory('verifyUser', ['$rootScope', '$window', '$q', '$location', '$timeout', '$http', 'Token', 'getUserEmail', 'getUserSites', function($rootScope, $window, $q, $location, $timeout, $http, Token, getUserEmail, getUserSites) {
  return {
    siteError: function() {
      localStorage.removeItem('accessToken');
      $location.path('/');
    },
    // Redirect user to /sites if logged in.
    homepageRedirect: function() {
      var deferred = $q.defer();
      var token = Token.get();
      if(!token) {
        deferred.resolve(true);
      } else {
        deferred.reject(true);
        $location.path('/sites');
      }
      return deferred.promise;
    },
    // Verify user token exists and they have access to the section.
    buildUserData: function(site) {
      console.log('site',site,'/site');
      var deferred = $q.defer();
      var token = Token.get();
      var _this = this;
      if(!token) {
        deferred.reject('no token');
        localStorage.removeItem('accessToken');
        $location.path('/');
      } else {
        if($rootScope.sites) {
          console.log('site list present, check access.');
          if(site) {
            var data = $rootScope.sites;
            console.log(data, site);
            for(var i in data) {
              console.log(data[i].sitename);
              if(data[i].sitename === site) {
                console.log('user has access, render view.');
                deferred.resolve(true);
                return false;
              }
            }
            console.log('No site access, logout.');
            deferred.reject('No access to site.');
            _this.siteError();
          } else {
            console.log('No access needed, landing page.');
            deferred.resolve(true);
          }
        } else {
          console.log('no site list, get user email from google and query db with user.');
          getUserEmail.getEmail().then(function(data) {
            return getUserSites.getSites();
          }).then(function(data) {
            if(site) {
              console.log('sub page');
              for(var i in data.sites) {
                console.log(data.site[i]);
                if(data.sites[i].sitename === site) {
                  console.log('user has access, render view.');
                  deferred.resolve(true);
                  return false;
                }
              }
              console.log('No site access, logout.');
              deferred.reject('No access to site.');
              _this.siteError();
            } else {
              deferred.resolve(true);
            }
          }).catch(function(data) {
            deferred.reject(true);
            _this.siteError();
          });
        }
      }
      return deferred.promise;
    }
  }
}]);

最新更新