21

Моя проблема на самом деле очень похож на найденной здесь:

AngularJs - cancel route change event

Короче говоря, я использую $ routeChangeStart и пытается изменить ток маршрут с использованием $ location. Когда я это делаю, консоль показывает мне, что исходная страница по-прежнему загружается и быстро перезаписывается новой страницей.

Предлагаемое решение состояло в том, чтобы использовать $ locationChangeStart вместо $ routeChangeStart, который должен работать для предотвращения дополнительной перенаправления. К сожалению, я использую дополнительные данные в $ rubeprovider, к которому мне нужно получить доступ, изменяя маршрут (я использую его для отслеживания ограничений страницы). Вот пример ...

$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 для достижения того, что мне нужно?

ответ

21

Один подход, который приходит на ум пытается использовать параметр разрешить для этого:

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

Пожалуйста, обратите внимание, что я не проверял код, приведенный выше, но я делаю аналогичные вещи в своих проектах.

+0

Извините за поздний ответ. Когда что-то работает для меня, я склонен волноваться и двигаться дальше. Это оказалось идеальным решением для того, что я делал.В функции загрузки я смог добавить такие вещи, как '$ http' и' $ location', чтобы обрабатывать мои запросы. – ThisLanham

+0

Мне пришлось сделать функцию загрузки более похожей на ту, что была у Nick http://stackoverflow.com/a/19482187/1449799 (отклонение не работало так, как написано здесь) – Michael

+1

Функция 'load' должна выглядеть следующим образом: 'var deferred = $ q.defer(); if (access) {deferred.resolve(); } else {deferred.reject(); $ Location.url ('/ Войти'); } return deferred.promise; ' – Clay

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

Когда маршрут/заказы щелкают обещание отвергаются (с выскакивающим, может быть модальным) и маршрут не следует.

Надеюсь, это поможет кому-то.

+0

любой совет по этому поводу? – Awena

14

Я столкнулся с одной и той же ситуацией, и мое решение было согласовано с тем, что предназначалось ОП.

Я использую событие $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" 
+0

Что делать, если в URL-адресе есть параметр запроса ... как определить, какой маршрутизатор называется – niran

+0

@niran - Я обновил свой ответ для вас. Взглянуть. – tamakisquare

+3

Как это работает для маршрутов с параметрами? как/article /: articleId? – mkhatib

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

Я реализовал этот метод в моем собственном проекте, и это работает прекрасно. Надеюсь, это поможет кому-то еще, кто наткнулся на него.

Смежные вопросы