我是角度的新手,可能完全错了。 在/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;
}
}
}]);