I'm writing a small AngularJS app that has a login view and a main view, configured like so:
$routeProvider
.when('/main' , {templateUrl: 'partials/main.html', controller: MainController})
.when('/login', {templateUrl: 'partials/login.html', controller: LoginController})
.otherwise({redirectTo: '/login'});
My LoginController checks the user/pass combination and sets a property on the $rootScope reflecting this:
function LoginController($scope, $location, $rootScope) {
$scope.attemptLogin = function() {
if ( $scope.username == $scope.password ) { // test
$rootScope.loggedUser = $scope.username;
$location.path( "/main" );
} else {
$scope.loginError = "Invalid user/pass.";
}
}
Everything works, but if I access http://localhost/#/main
I end up bypassing the login screen. I wanted to write something like "whenever the route changes, if $rootScope.loggedUser is null then redirect to /login"
...
... wait. Can I listen to route changes somehow? I'll post this question anyway and keep looking.
In your app.js file:
Here is maybe a more elegant and flexible solution with 'resolve' configuration property and 'promises' enabling eventual data loading on routing and routing rules depending on data.
You specify a function in 'resolve' in routing config and in the function load and check data, do all redirects. If you need to load data, you return a promise, if you need to do redirect - reject promise before that. All details can be found on $routerProvider and $q documentation pages.
For russian-speaking folks there is a post on habr "Вариант условного раутинга в AngularJS."
I have been trying to do the same. Came up with another simpler solution after working with a colleague. I have a watch set up on
$location.path()
. That does the trick. I am just starting to learn AngularJS and find this to be more cleaner and readable.If you do not want to use angular-ui-router, but would like to have your controllers lazy loaded via RequireJS, there are couple of problems with event
$routeChangeStart
when using your controllers as RequireJS modules (lazy loaded).You cannot be sure the controller will be loaded before
$routeChangeStart
gets triggered -- in fact it wont be loaded. That means you cannot access properties ofnext
route likelocals
or$$route
because they are not yet setup.Example:
This means you cannot check access rights in there.
Solution:
As loading of controller is done via resolve, you can do the same with your access control check:
Note here that instead of using event
$routeChangeStart
I'm using$routeChangeError
1. Set global current user.
In your authentication service, set the currently authenticated user on the root scope.
2. Set auth function on each protected route.
3. Check auth on each route change.
Alternatively you can set permissions on the user object and assign each route a permission, then check the permission in the event callback.
After some diving through some documentation and source code, I think I got it working. Perhaps this will be useful for someone else?
I added the following to my module configuration:
The one thing that seems odd is that I had to test the partial name (
login.html
) because the "next" Route object did not have a url or something else. Maybe there's a better way?