可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Basically what I'm trying to do is change the state depending on user authentication status.
When I do $state.go();
without $rootScope, I can redirect to the page without the error but when I do with
$rootScope.$on('$stateChangeStart', function (event) {
$state.go();
event.preventDefault()
})
Below Is the Controller Code:
DiaryDashboard.controller('AppController',
['$scope', '$rootScope', '$localStorage', '$http', '$state'
, function ($scope, $rootScope, $localStorage, $http, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState) {
if ($localStorage.userdetails &&
$localStorage.userdetails.isAuthenticated == true) {
//Check for Authentication state
//If not redirect to the state in the else clause
//Populate the $rootScope with user details
$rootScope.userdetails = $localStorage.userdetails;
//Switch to the parent state
$state.go();
event.preventDefault();
} else {
//If User not authenticated
//GO to the Authentication State
$state.go('auth');
event.preventDefault();
}
})
}]);
回答1:
The most important thing here is to understand this:
Do not redirect if not needed. Other words, if user is already redirected to intended state - we should leave... There is a working plunker with similar solution.
Check this Q & A:
Angularjs ui-router. How to redirect to login page
the adjusted code:
$rootScope.$on('$stateChangeStart', function (event, toState) {
var isNavigatingToAuth = toState.name === "Auth";
if(isNavigatingToAuth){
return; // no need to redirect
}
if ($localStorage.userdetails &&
$localStorage.userdetails.isAuthenticated == true)
...
回答2:
You are creating a redirection loop.
You need to check whether the new route is already the route where you want to send your client to.
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if (next == 'my-auth-page') {
// already going to auth page no redirect needed
} else {
// not going to auth page, we should redirect now
$location.path('my-auth-page');
}
});
回答3:
You are basically creating a state change interceptor.
The thing is, on every one of your branches in '$stateChangeStart' you have a $state.go . Since this is an interceptor, every time you invoke $state.go , the handler for $stateChangeStart will be invoked, and this is why you get this invocation loop that ends with that error.
You need to write the handler in a way that has at least one branch that does not invoke $state.go
Here is how we implemented it:
//The list of states that do not need authentication (like auth)
var authorizedStates = ['auth', 'someOtherAuthorizesState', 'etc'];
// This method reports if a state is one of the authorizes states
var isChildOfAuthorizedStated = function (stateName) {
var isChild = false;
authorizedStates.forEach(function (state) {
if (stateName.indexOf(state) === 0) {
isChild = true;
}
});
return isChild;
};
$rootScope.$on('$stateChangeStart',
// The stateChangeStart handler
function (event, toState, toParams, fromState, fromParams) {
// Check if the future state is not an authorized state
// and if the user is not authenticated.
if (!isChildOfAuthorizedStated(toState.name) && !Auth.isAuthenticated()) {
event.preventDefault();
$state.go('auth');
}
);
回答4:
Your code is going in infinite as you are doing $state.go
in both cases, You could should not do $state
redirection user is authorized & second condition is proper which is in else block
if ((!$localStorage.userdetails || !$localStorage.userdetails.isAuthenticated)
&& toState.name != 'auth') { //<--this condition will stop infinite loop
//If User not authenticated
//GO to the Authentication State
$state.go('auth');
event.preventDefault();
}
Update
Other thing which I wanted to point out about your code is $stateChangeStart
should be inside a run block(which initialize exactly after config block) so that It would be common for all state & will initialized this condition at the starting of your app
Code
app.run(function($rootScope){
$rootScope.$on('$stateChangeStart', function (event, toState) {
if ($localStorage.userdetails && $localStorage.userdetails.isAuthenticated == true) {
if ((!$localStorage.userdetails || !$localStorage.userdetails.isAuthenticated)
&& toState.name != 'auth') { //<--this condition will stop infinite loop
//If User not authenticated
//GO to the Authentication State
$state.go('auth');
event.preventDefault();
}
})
});
Also do use service to store UserDetails
using $rootScope
in AngulaJs is considered as bad code practice.
回答5:
Use $state.go("main", {}, {notify:false}); for not notify to "$stateChangeStart"event and not allow the event loop.
$state.go("main", {}, {notify:false});