0

i have done route restriction in angular js app. when user is already logged in it should not move to login page.this is my code:

.run(function($rootScope, $location, Auth) {
    $rootScope.$on('$routeChangeStart', function(event, next) {

       Auth.isLoggedInAsync(function(loggedIn) {

        if(loggedIn){ //when user loged in it should not move to login page
          if ($location.path() == "/participant/login"){
            event.preventDefault();
          }
        }
      });
    });

this code does not give any type of error.but it move to the login page when user is already logged in.i think here event.preventDefault() is not working.please suggest me if i am doing any mistake or if you have any good way to handle this issue ?

Mukund Kumar
  • 21,413
  • 18
  • 59
  • 79
  • Possible duplicate of http://stackoverflow.com/questions/14895016/event-preventdefault-not-working-for-routechangestart-in-angularjs-app – Pr0gr4mm3r Sep 19 '14 at 20:27
  • @Pr0gr4mm3r although it seems like a dupe, I guess that question's answers will not work here as OP is running the validation asynchronously. – Fabrício Matté Sep 19 '14 at 20:30

2 Answers2

1

I don't think @wiherek's answer will work in general because it doesn't give any way to guarantee that the Auth service is ready by the time that the $routeChangeStart handler is called.

What you can rely on though is that if any of the items in the route's resolve parameter return promises, then either:

  • The promise will be resolved before the the route change happens, or
  • The promise will be rejected before $rootScope.$routeChangeStart is broadcast.

So in your route definition you could so something like this:

$routeProvider.when('/participant/login', {
  resolve: {
    auth: function(Auth, $q) {
      var deferred = $q.defer();
      Auth.isLoggedInAsync(function(loggedIn) {
        if (loggedIn) {
          deferred.resolve();
        }
        else {
          deferred.reject({alreadyLoggedIn: true});
        }
      }).catch(function() {
        deferred.reject();
      });
      return deferred.promise;
    }
  }
);

And you could catch it by listening for $routeChangeError:

app.run(function($rootScope, $location, Auth) {
  $rootScope.$on("$routeChangeError", function(event, current, previous, rejection) {
    if (rejection != null && rejection.alreadyLoggedIn) {
      // We should get here if and only if
      // `deferred.reject({alreadyLoggedIn: true})` was called from the
      // above.
    }
  });
});
Andrew Magee
  • 6,506
  • 4
  • 35
  • 58
0

I am not sure what your Auth object (service?) is, but the method is called async... so what probably happens is, Auth.isLoggedInAsync() get's fired, then the outer function continues. As there is nothing after Auth.isLoggedInAsync(), it basically returns undefined, and the route change carries on.

event.preventDefault() may be called, but the outer function doesn't wait for Auth.isLoggedInAsync() to resolve, so the default action probably already happened. There is nothing to be prevented anymore.

Consider either using a blocking function (synchronous), or assign the user state to an object property, that already has it's value resolved.

.run(function($rootScope, $location, Auth) {
  $rootScope.$on('$routeChangeStart', function(event, next) {
    if (Auth.userLoggedIn) { //when user loged in it should not move to login page
      if ($location.path() === "/participant/login"){
        event.preventDefault();
      }
    }
  });
});

Please note that the above code requires you to change Auth, because Auth.userLoggedIn is a property (which you will probably need to define, unless I hit a bullseye ;))

wiherek
  • 1,923
  • 19
  • 25
  • 1
    Another thing is, as per the comments and answer referenced above, it might not work even if you call it synchronously, because it might not be possible to preventDefault that particular event. The other answers suggest to listen to $locationChangeStart event instead. – wiherek Sep 19 '14 at 20:39