My problem is actually very similar to the one found here:
AngularJs - cancel route change event
In short, I'm using $routeChangeStart and trying to change the current route using $location. When I do, the console shows me that the original page is still loads and is quickly overwritten by the new page.
The solution provided was to use $locationChangeStart instead of $routeChangeStart, which should work for preventing the extra redirect. Unfortunately, I'm using additional data in the $routeprovider that I need to access while changing the route (I use it to track page restrictions). Here's an example...
$routeProvider.
when('/login', { controller: 'LoginCtrl', templateUrl: '/app/partial/login.html', access: false}).
when('/home', { controller: 'HomeCtrl', templateUrl: '/app/partial/home.html', access: true}).
otherwise({ redirectTo: '/login' });
$rootScope.$on('$routeChangeStart', function(event, next, current) {
if(next.access){
//Do Stuff
}
else{
$location.path("/login");
//This will load the current route first (ie: '/home'), and then
//redirect the user to the correct 'login' route.
}
});
With $routeChangeStart, I can use the "next" and "current" parameters (see AngularJS - $route) as objects to retrieve my 'access' values. With $locationChangeStart, those two parameters return url strings, not objects. So there seems to be no way to retrieve my 'access' values.
Is there any way I can combine the redirect-stopping power of $locationChangeStart with the object-flexibility of $routeChangeStart to achieve what I need?
One approach that comes to mind is trying to use the resolve parameter for this:
var resolver = function(access) {
return {
load: function($q) {
if (access) { // fire $routeChangeSuccess
var deferred = $q.defer();
deferred.resolve();
return deferred.promise;
} else { // fire $routeChangeError
return $q.reject("/login");
}
}
}
}
$routeProvider.
when('/login', { controller: 'LoginCtrl', templateUrl: '/app/partial/login.html', resolve: resolver(false)}).
when('/home', { controller: 'HomeCtrl', templateUrl: '/app/partial/home.html', resolve: resolver(true)}).
otherwise({ redirectTo: '/login' });
Please note that I haven't tested the code above but I'm doing similar stuff in my projects.
I faced the same situation myself and my solution was aligned with what the OP intended to do.
I use the $locationChangeStart
event and the $route
service. By accessing $route.routes
, I get a hold of all route objects defined with $routeProvider
.
.run(function($rootScope, $route, $location) {
$rootScope.$on('$locationChangeStart', function(ev, next, current) {
// We need the path component of `next`. We can either process `next` and
// spit out its path component, or simply use $location.path(). I go with
// the latter.
var nextPath = $location.path();
var nextRoute = $route.routes[nextPath]
console.log(nextRoute.access); // There you go!
});
})
To parse the path component out of an absolute URL:
var urlParsingNode = document.createElement('a');
urlParsingNode.href = next; // say, next = 'http://www.abc.com/foo?name=joe
console.log(urlParsingNode.pathname) // returns "/foo"
Since version 1.3.0 you can actually use the newly introduced preventDefault-method. With that you can cancel the current route change and then apply your own custom redirect as shown in this github-issue:
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if (next.access) {
event.preventDefault();
$rootScope.$evalAsync(function() {
$location.path('/login');
});
}
});
I implemented this method in my own project and it works perfectly. Hope it helps anyone else who stumbles across it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With