locationChangeStart and preventing route change
Asked Answered
B

4

6

I'm trying to create basic validation whether user can access some route or not. I had progress in that, but there's one thing that I can't figure out.

I'm using $locationChangeStart to monitor route changes. Scenario is: 1. if user is logged in, then allow him to access all routes, except auth routes (login, register). I'm checking this by calling method isAuthenticated() from my AuthFactory 2. If user is not logged in, then he access only login and register routes. Any other route should be prevented, and user should be redirected to login in that case.

$rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl){
  if(AuthFactory.isAuthenticated()){
    if(AuthFactory.isAuthRoute(newUrl)){
      event.preventDefault();
      $location.path('/');
    }
  } else {
    if(!AuthFactory.isAuthRoute(newUrl)){
      event.preventDefault();
      $location.path('/login');
    }

  }
});

Thing that troubles me, is the one with preventDefault(). If app reaches code with preventDefault(), location.path() that comes after that, simply doesn't work.

However, if I remove event.preventDefault(), location.path() works. Problem with this, is that I need that prevent, in case non-logged tries to access some non-auth page.

Basically, I want to be able to prevent or redirect based on requested route. What is the proper way to do that?

Burrussburry answered 25/12, 2013 at 12:11 Comment(6)
I am uncertain what you are doing and what you desire. Can you provide us with a plunkr?Ruddock
Hey baba, I edited my question, please check if it is more concise now?Burrussburry
In my opinion, you shoudn't be using the $location service. It is too low-level. I'd check the github.com/angular-ui/ui-router which is far more suited for the task you are describing.Ruddock
I see, just I thought that I can manage this by using just angular events. I'll take a look, thanksBurrussburry
Did you try using $timeout to trigger $location.path() after preventDefault(). This way you separate the cancellation of the path change in the event and setting the new path. Should work.Earl
BTW, I just tried implementing the same. In my case I either cancel the location change via preventDefault(), or redirect to somewhere else by changing location and $location.refresh(), WITHOUT preventDefault(). Works like a charm.Earl
B
4

Ok, you need to do this:

var authPreventer = $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl){
    if(AuthFactory.isAuthenticated()){
        if(AuthFactory.isAuthRoute(newUrl)){
            event.preventDefault();
            authPreventer(); //Stop listening for location changes
            $location.path('/');
        }
    } 
    else {
        if(!AuthFactory.isAuthRoute(newUrl)){
            event.preventDefault();
            authPreventer(); //Stop listening for location changes
            $location.path('/login');
        }
    }
});
Brighten answered 30/3, 2014 at 10:43 Comment(1)
For the record, that blog post looks like it passed through a translator into another language and back into English. The original post that sysmagazine ripped off is here: weblogs.asp.net/dwahlin/…Mcwhorter
S
2

You can try using auth in resolves in-order to prevent access to certain routes. here is the doc,it's not very clear, but you can find plenty of examples out there.

Sculpsit answered 27/12, 2013 at 1:24 Comment(1)
Hey yotamsha, that's right, but then I need to attach resolve and that check for every existing and new written route. I was hoping that I do it on one place, my use case was pretty usual, that's why I can't believe that this is so difficult to do, but looks like it is :) thanks for helping!Burrussburry
V
0

I recently had the same problem and I was finally able to solve it by listening to $routeChangeStart instead of $locationChangeStart (without needing to call $route.reload()).

The documentation for both events is kinda vague... I suppose the $ruteChangeStart event is called before the $locationChangeStart (I'm going to read the source code to fully understand what's happening here).

Verrucose answered 23/6, 2014 at 14:58 Comment(0)
B
-2

Ok, I managed to do this using $routeChangeStart. The catch is in using $route.reload(). So above code, should look something like this:

$rootScope.$on('$routeChangeStart', function(event, next, current){
  if(AuthFactory.isAuthenticated()){
    if(AuthFactory.isAuthRoute(next.originalPath)){
      $route.reload();
      $location.path('/');
    }       
  } else {
    if(!AuthFactory.isAuthRoute(next.originalPath)){
      $route.reload();
      $location.path('/login');
    }
  }
});

I put this in my .run method, so all the request are handled here, and I don't need to think about every new route that I (or someone else adds). That's why this looks more clean to me.
If someone has different approach, please share.

Note: just in case, I do my check on backend part also :)

Burrussburry answered 22/1, 2014 at 16:10 Comment(1)
the controller still gets called so you actually change the route after the route started changing.Perimorph

© 2022 - 2024 — McMap. All rights reserved.