Cancel route and redirect to other route without displaying the original content in AngularJS
Asked Answered
S

1

14

I want to check an http services to see if a user is authenticated and if it has permission to see the certain page (controller) in AngularJS 1.2.0rc1.

I have this scenario: User A wants to visit http://www.example.com/content. Now this content should not be accessible when he or she is not authenticated. If the user is not authenticated, they should be redirected to http://www.example.com/login.

Now I managed to do this, but I see the rendered html of the content page briefly. I don't want this. How do I redirect to the login page, without rendering the content page?

I register my routes as such:

$routeProvider.when('/login', route.resolve('Login', false))
$routeProvider.when('/content', route.resolve('Content', true))

Now I've tried this:

$rootScope.$on('$routeChangeStart', function (event, route) {
    if (route.requiresLogin) {
        $http.get('/api/user/loggedin/').then(function (response) {
            if (response !== 'true') {
                $location.path('/login');
            }
        });
    }
});

Which works, but I still see the content of the html of the other page (content) flashing.

I've read that here that you can also try to change the resolve functionality when the route is resolved:

    var resolve = function (baseName, requiresLogin) {
    var routeDef = {};
    var dependencies = [routeConfig.getControllersDirectory() + baseName + 'Controller.js'];

    routeDef.templateUrl = routeConfig.getViewsDirectory() + baseName.toLowerCase() + '.html';
    routeDef.controller = baseName + 'Controller';
    routeDef.requiresLogin = requiresLogin;
    routeDef.resolve = {
        load: ['$q', '$rootScope', '$http', '$location', function ($q, $rootScope, $http, $location) {
            console.log(requiresLogin);
            if (requiresLogin) {
                return checkLoggedIn($q, $rootScope, $http, $location);
            } else {
                return resolveDependencies($q, $rootScope, dependencies);
            }
        }]
    };

    return routeDef;
}

But here the page is also displayed briefly.

Hope that you can help me out.

Soulless answered 15/8, 2013 at 15:31 Comment(0)
C
22

The first answer should work, but to do it using $q I would use defer.resolve() or defer.reject("rejection_reason") then I would listen for a $routeChangeError in a top-level controller that is bound to an an element outside of the ng-view that the routeProvider manages.

So in your HTML, something like:

<body ng-app="app" ng-controller="DocumentCtrl">
  <div ng-view>
  </div>
</body>

Then that route of yours would be defined something like:

when('/home', {
  templateUrl: templateUrl blah,
  controller: baseName + 'Controller',
  resolve: {
    load: function($q, MY_USER_SERVICE){
      var defer = $q.defer();
      if(~MY USER LOGGED_IN LOGIC RETURNS TRUE~){
        defer.resolve();
      } else {
        defer.reject("not_logged_in");
      }
      return defer.promise;

    }
  }
}).

Then my DocumentCtrl controller would contain:

$scope.$on("$routeChangeError", function(evt,current,previous,rejection){
  if(rejection == "not_logged_in"){
    //DO SOMETHING
  } else {
    //OR DO SOMETHING ELSE
  }
});

I'm running the above and there's no flash of any views that shouldn't be loaded.

Commutation answered 24/2, 2014 at 10:53 Comment(3)
Confirmed as the way to deal with this, while not showing the original routed page. Promises are not necessary, a simple throw new Error ('') is sufficient. Key is that only an error will stop the current navigation. Maybey a future version of Angular will bring us a decent way to handle conditional (injected) redirection.Traci
Oh, interesting. Se we can simply return true in the load function, or conditionally throw an error above that if we don't want to allow access? In every example I have seen a promises have been used.Commutation
Using UI-router has made all these easy. Simply writing $state.go('state') inside resolve redirects you before loading the controller.Beaufort

© 2022 - 2024 — McMap. All rights reserved.