Я пытаюсь реализовать базовую проверку безопасности, чтобы заблокировать пользователям доступ к определенным состояниям в зависимости от их набора разрешений:
'use strict';
var autoExecApp = angular.module("myApp", ['ui.router']);
autoExecApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){
$stateProvider
.state('index', {
url: '/index',
templateUrl: 'partials/index.html'
})
.state('permission', {
url: '/permission',
templateUrl: 'partials/permissions.html'
});
}]);
autoExecApp.run(['$rootScope', '$state', '$userRoles', function($rootScope, $state, $userRoles) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
event.preventDefault(); // prevent page from being loaded anyway
$userRoles.hasPermissions(toState.name).then(function(data) {
var result = data === "true";
if (!result) {
$state.go('permission');
}
else {
$state.go(toState.name, toParams ,{notify:false});
}
});
});
}]);
Теперь проблема связана с тем, что изменение моего состояния происходит внутри обещания. Я бы с радостью сделал его синхронным - как и должно быть в этом случае, но я не понимаю, почему он не работает асинхронно.
Если я перемещу event.preventDefault()
внутри обещания, это сработает. НО состояние меняется за 2 шага. Во-первых, он всегда будет переходить на исходную страницу, а затем вскоре после перехода на «заблокированную» страницу (если она была заблокирована). Я так понимаю, это потому, что он успешно возвращается один раз из $on и обновляет состояние, а затем снова обновляет его, когда возвращается из обещания.
Однако если обещание такое, каким вы его видите, состояние не изменится. Все работает, но страница не обновляется. Я не уверен, почему это так. По какой-то причине, если событие не предотвратить, сработает более позднее изменение состояния. Однако, если это предотвращено и $state.go вызывается из возвращенного промиса, кажется, что уже слишком поздно обновлять $state.
РЕДАКТИРОВАТЬ: я успешно использовал широковещательное решение, и вот как оно выглядело:
event.preventDefault();
$state.go(toState.name, toParams, {notify: false}).then(function() {
// line 907 state.js
$rootScope.$broadcast('$stateChangeSuccess', toState, toParams, fromState, fromParams);
});
По-видимому, из-за того, что это обещание, функция preventDefault(); подавляет естественное срабатывание этого '$stateChangeSuccess'. Выполнение этого вручную восстанавливает ожидаемое поведение.