$ q.defer()完成后,角度控制器功能

时间:2014-12-12 01:52:33

标签: angularjs angular-routing

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

我正在使用google auth模块,如果用户登录userSites var为空,那么我ping谷歌,然后调用/api/index.php/login返回用户站点列表,然后在这种情况下完成$ q.defer()。解决(真);.问题是站点控制器功能在定义之前尝试访问userSites。有没有办法在$ q.defer()。resolve完成后调用$ scope.test()?或者有更好的方法吗?

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

路线 - >验证用户访问令牌,如果未定义则加载userSites - >验证部分访问 - >完全推迟。

网站控制器

'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();

}]);

** App.js routing and auth ** - 不是整个文件...

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

2 个答案:

答案 0 :(得分:1)

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

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

2)如果您希望使用异步值解析resolve参数(因为它似乎与auth一起),则该函数需要返回一个promise。然后$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;
    }
  };
});

答案 1 :(得分:0)

路由器调用在resolve中返回verifyUser.buildUserData,这将检查是否有令牌,如果没有将用户注销。然后检查是否有站点列表全局变量,如果没有ping令牌谷歌获取用户电子邮件和用户电子邮件到数据库获取站点列表,从那里循环列表并检查auth如果站点名称是传递给buildUserData。

以下示例将在呈现视图之前处理所有auth。感谢New Dev指出我正确的方向。

<强>路由器:

...

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;

    }

  }
}]);