20

我的问题实际上与此处发现的问题非常相似:

AngularJs - 取消路线更改事件

简而言之,我正在使用 $routeChangeStart 并尝试使用 $location 更改当前路线。当我这样做时,控制台向我显示原始页面仍在加载并很快被新页面覆盖。

提供的解决方案是使用 $locationChangeStart 而不是 $routeChangeStart,这应该可以防止额外的重定向。不幸的是,我在 $routeprovider 中使用了我在更改路由时需要访问的其他数据(我用它来跟踪页面限制)。这是一个例子......

$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.
    }
});

使用 $routeChangeStart,我可以使用“下一个”和“当前”参数(参见AngularJS - $route)作为对象来检索我的“访问”值。使用 $locationChangeStart,这两个参数返回 url 字符串,而不是对象。所以似乎没有办法检索我的“访问”值。

有什么方法可以将 $locationChangeStart 的重定向停止功能与 $routeChangeStart 的对象灵活性相结合来实现我的需要?

4

4 回答 4

22

想到的一种方法是尝试为此使用 resolve 参数:

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' });

请注意,我没有测试上面的代码,但我在我的项目中做了类似的事情。

于 2013-07-31T19:40:58.487 回答
14

我自己也面临同样的情况,我的解决方案与 OP 的意图一致。

我使用$locationChangeStart事件和$route服务。通过访问$route.routes,我获得了所有用 定义的路由对象$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!
  });
})

要从绝对 URL 中解析路径组件:

var urlParsingNode = document.createElement('a');
urlParsingNode.href = next;  // say, next = 'http://www.abc.com/foo?name=joe
console.log(urlParsingNode.pathname)  // returns "/foo"
于 2013-12-06T02:17:03.707 回答
7

从 1.3.0 版开始,您实际上可以使用新引入的preventDefault方法。有了它,您可以取消当前的路由更改,然后应用您自己的自定义重定向,如此github-issue所示:


$rootScope.$on("$routeChangeStart", function (event, next, current) {
    if (next.access) {
      event.preventDefault();
      $rootScope.$evalAsync(function() {
        $location.path('/login');
      });
    }
});

我在自己的项目中实现了这种方法,并且效果很好。希望它可以帮助任何偶然发现它的人。

于 2014-12-23T11:35:47.410 回答
3

很好的回答马吕斯,让我走上正轨。我正在为访问控制做这样的事情。但是,这有效...

  var resolver = function(route, routeEvent) {
  return {
    load: function($q) {
      deferred = $q.defer();
      if (routeEvent!=3) { // eventually will be a list of routeEvents that the logged-in user is not allowed to visit read from a db table configured by admin
        deferred = $q.defer();
        deferred.resolve();
        return deferred.promise;
      } else { // fire $routeChangeError
        alert("You don't have permissions to access this.");
        deferred.reject(route);
        return deferred.promise;
      }
    }
  }
}

  var jsonRoutes = [

    {'route' : '/logout', 'templateUrl': 'partials/login.html',   'controller' : 'LoginCtrl', 'routeEvent' : 1 },
    {'route' : '/orders', 'templateUrl': 'partials/orders.html',   'controller': 'OrderListCtrl', 'routeEvent' : 2 },
    {'route' : '/products', 'templateUrl': 'partials/products.html',   'controller': 'ProductListCtrl', 'routeEvent' : 3 },

...

];


// somewhere on successful login code add in the dynamic routes

angular.forEach(jsonRoutes, function(r) {
                $route.routes[r.route] = {templateUrl: r.templateUrl, controller: r.controller, routeEvent: r.routeEvent, resolve: resolver(r.route, r.routeEvent)};
                  });


// got some static routes too which don't have access control - user has to login right?

  config(['$routeProvider', function($routeProvider) {


  $routeProvider.
    when('/error',  {templateUrl: 'partials/error.html',   controller : ErrorCtrl,  routeEvent : 1 }).
    when('/login',  {templateUrl: 'partials/login.html',   controller : LoginCtrl, routeEvent : 1 }).
    when('/home',  {templateUrl: 'partials/home.html',   controller : HomeCtrl, routeEvent : 1 }).
    when('/logout', {templateUrl: 'partials/login.html',   controller : LoginCtrl, routeEvent : 1 }).
    otherwise( {redirectTo: '/error'} );   

当单击 /orders 路由时,promise 被拒绝(带有弹出窗口,可能是模态对话框)并且不遵循该路由。

希望这可以帮助某人。

于 2013-10-20T20:02:10.017 回答