在我们在python中使用angularjs和Rest API构建的单页面应用程序中,我们在Rest API中有一个ACL逻辑,用于确定当前登录用户是否可以访问某个资源。
我们目前正在做的是包装每个"受保护"的标记。包含ng-if="authorized"
属性的div中的模板,如果API响应当前用户有权查看模板内容,则$scope.authorized
变量为true。
使用此解决方案,最终用户体验的是在API确定是否有权访问资源以及将其重定向到仪表板页面所花费的时间之间的快速空白模板(页面所有类型的用户都可以访问)以及一条消息,告诉他们他们无权访问该特定资源。 当然,我们关注的是在应用程序将空白模板带到仪表板页面之前向最终用户显示空白模板的时间。
我们可以在AngularJS中做些什么来避免在向最终用户显示空白模板时的跨度时间,而是让它们保留在当前页面中,并且仅在API解析它们时才转到他们请求的页面可以访问吗?
答案 0 :(得分:1)
你必须使用ngRoute
吗? ui-router
有两个很好的工具,您可以单独使用或一起使用来解决此问题:
它有一个$stateChangeStart
事件,在状态转换发生之前被触发,包含有关上一个/下一个状态的所有信息。你可以在这里停止状态转换。例如,我使用类似的东西来发送对登录体验的auth-required访问:
$stateProvider.state('auth-required-state', {
url: '^/auth-required-state',
templateUrl: '/views/view/auth-required-state.html',
controller: 'AuthRequiredStateController',
// NOTE: You have access to this entire block in $stateChangeStart, so you can
// define your own attributes that your own code looks at
allowAnonymous: false
});
和$stateChangeStart
:
// Handle some checking that needs to be performed
$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
// If we aren't logged in and we need to be, do that
if (!$rootScope.currentUser.loggedIn && !toState.allowAnonymous) {
$state.go('login');
e.preventDefault();
}
});
它有一个resolve
运算符,您可以使用它来延迟加载,例如,如果您需要来自REST服务的数据块,而不仅仅是模板。对于我的另一个用例,如果用户可以访问数据,我只想进入目标屏幕 - 模板始终可用,因为您可以访问某些记录但不能访问其他记录。你可以这样做:
var ShowDataControllerConfig = function($stateProvider) {
var getDataBlock = function($stateParams, myDataManager) {
return myDataManager.getDataBlockAndReturnAPromise($stateParams.data_id);
};
// Tolerate minification - you can't use the array trick in state definitions
getGroupEntry.$inject = ['$stateParams', 'myDataManager'];
$stateProvider.state('show-data', {
url: '^/show-data/{data_id}',
templateUrl: '/views/view/show-data.html',
controller: 'ShowDataRoomController',
resolve: {
dataBlock: getDataBlock
}
});
};
ShowDataControllerConfig.$inject = ['$stateProvider'];
var ShowDataController = function(dataBlock) {
// dataBlock contains our data - but unlike ngRoute, we never even get here if
// it couldn't be loaded. You can do error handling in $stateChangeError.
};
ShowDataController.$inject = ['dataBlock'];
angular
.module('myApp.controllers.showData', [])
.config(ShowDataControllerConfig)
.controller('ShowDataController', ShowDataController);