[英]$state.go not working from promise
我正在嘗試實施基本安全檢查,以阻止用戶訪問某些狀態,具體取決於他們的權限集:
'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});
}
});
});
}]);
現在問題圍繞着我的狀態變化發生在承諾內部的事實。 我很樂意讓它同步 - 因為它確實應該在這種情況下,但我很困惑為什么它不是異步工作。
如果我在promise中移動event.preventDefault()
,它就可以了。 但是狀態改變分為兩步。 首先,它將始終轉到原始頁面,然后在轉換到“已阻止”頁面后很快(如果它被阻止)。 我收集這是因為它從$ on成功返回一次並更新狀態,然后在從promise返回時再次更新它。
如果承諾是你如何看待它,狀態將不會改變。 一切似乎都有效,但頁面不會更新視圖。 我不確定為什么會這樣。 出於某種原因,如果未阻止事件,則稍后的狀態更改將起作用。 但是,如果它被阻止並且從返回的promise中調用$ 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'。 手動執行它可以恢復預期的行為。
這是一個已知的問題。 一般工作的解決方法是從'$ stateChangeStart'處理程序中廣播自定義事件,然后從該自定義事件的處理程序中進行狀態轉換。
$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) {
$rootScope.$broadcast('goToPermission');
}
else {
$rootScope.$broadcast('goToState', toState.name);
}
});
});
借鑒自: https : //github.com/angular-ui/ui-router/issues/178#issuecomment-49156829
我認為弗拉基米爾·古羅維奇的“廣播”解決方案是要走的路,特別是因為他表示這是一個既定的解決方案。
但我想知道一個解決方案,其中緩存權限然后同步查找,也可能是可行的。
autoExecApp.run(['$rootScope', '$state', '$userRoles', function($rootScope, $state, $userRoles) {
// Create a permissions cache, seeded with
// permission to go to the 'permission' state.
var permissionCache = {
'permission': true
};
// Create a researched list of all possible state names.
var stateNames = ['stateA', 'stateB', 'stateC'];
// Now load the cache asynchronously with
// `true` for each permission granted.
stateNames.forEach(function(state) {
$userRoles.hasPermissions(state).then(function(data) {
if(data === "true") {
permissionCache[state] = true;
}
});
});
// And finally, establish a $stateChangeStart handler
// that looks up permissions **synchronously**,
// in the permissionCache.
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
if (!permissionCache[toState.name]) {
event.preventDefault(); // prevent page from being loaded
$state.go('permission');
}
});
}]);
當然,這個解決方案會有自己的問題:
沒有研究/測試,我不能說這些問題是否重要。
為什么不使用解析功能來檢查用戶是否可以訪問您的路線?
像這樣的東西:
autoExecApp.config(['$stateProvider', '$urlRouterProvider', function (
$stateProvider, $urlRouterProvider) {
$stateProvider
.state('index', {
url: '/index',
templateUrl: 'partials/index.html'
})
.state('permission', {
url: '/permission',
templateUrl: 'partials/permissions.html'
})
.state('restricted-route', {
url: '/restricted',
templateUrl: 'partials/restricted.html',
resolve: {
authenticated: function ($q) {
var deferred = $q.defer();
$userRoles.hasPermissions(this)
.then(function (data) {
var result = data === "true";
if (result) {
deferred.resolve();
} else {
deferred.reject('unauthorized');
}
});
return deferred.promise;
}
}
});
}]);
$rootScope.$on('$stateChangeError',
function (event, toState, toParams, fromState, fromParams, rejection) {
if (rejection.error === 'unauthorized') {
$state.go('permission');
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.