21

Vấn đề của tôi là thực sự rất giống với một tìm thấy ở đây:

AngularJs - cancel route change event

Nói tóm lại, tôi đang sử dụng $ routeChangeStart và cố gắng thay đổi hiện tại tuyến đường bằng cách sử dụng $ location. Khi tôi thực hiện, giao diện điều khiển cho tôi biết rằng trang gốc vẫn đang tải và được ghi đè nhanh bởi trang mới.

Giải pháp được cung cấp là sử dụng $ locationChangeStart thay vì $ routeChangeStart, sẽ hoạt động để ngăn việc chuyển hướng thêm. Thật không may, tôi đang sử dụng dữ liệu bổ sung trong $ routeprovider mà tôi cần truy cập trong khi thay đổi tuyến đường (tôi sử dụng nó để theo dõi các hạn chế trang). Dưới đây là một ví dụ ...

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

Với $ routeChangeStart, tôi có thể sử dụng "bên cạnh" và "hiện tại" thông số (xem AngularJS - $route) như các đối tượng để lấy 'tiếp cận' giá trị của tôi. Với $ locationChangeStart, hai thông số đó trả về các chuỗi url, không phải các đối tượng. Vì vậy, dường như không có cách nào để lấy lại các giá trị 'truy cập' của tôi.

Có cách nào tôi có thể kết hợp sức mạnh chuyển hướng dừng của $ locationChangeStart với tính linh hoạt đối tượng của $ routeChangeStart để đạt được những gì tôi cần không?

Trả lời

21

Một cách tiếp cận mà nói đến cái tâm đang cố gắng sử dụng tham số quyết tâm cho việc này:

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

Xin lưu ý rằng tôi đã không kiểm tra mã trên nhưng tôi đang làm những thứ tương tự như trong các dự án của tôi.

+0

Xin lỗi vì trả lời muộn. Khi một cái gì đó làm việc cho tôi, tôi có xu hướng phấn khởi và tiếp tục. Điều này đã kết thúc là một giải pháp hoàn hảo cho những gì tôi đã làm.Trong hàm tải, tôi có thể thêm những thứ như '$ http' và' $ location' để xử lý thêm các yêu cầu của mình. – ThisLanham

+0

Tôi đã phải làm cho chức năng tải của tôi trông giống như một từ Nick http://stackoverflow.com/a/19482187/1449799 (từ chối không làm việc như được viết ở đây) – Michael

+1

'tải' chức năng nên đọc thêm như thế này: 'var deferred = $ q.defer(); if (access) {deferred.resolve(); } else {deferred.reject(); $ location.url ('/ login'); } return deferred.promise; ' – Clay

3

Câu trả lời hay đấy Marius, hãy để tôi đi đúng hướng. Tôi đang làm một cái gì đó như thế này để kiểm soát truy cập. Tuy nhiên, công trình này ...

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

Khi tuyến đường/đơn đặt hàng được nhấp vào lời hứa bị từ chối (với cửa sổ bật lên, có thể là hộp thoại phương thức) và tuyến đường không được theo dõi.

Hy vọng điều này sẽ giúp ai đó.

+0

bất kỳ lời khuyên nào về điều này? – Awena

14

Tôi phải đối mặt với tình huống tương tự và giải pháp của tôi phù hợp với những gì OP dự định làm.

Tôi sử dụng sự kiện $locationChangeStart và dịch vụ $route. Bằng cách truy cập $route.routes, tôi nhận được tất cả các đối tượng tuyến đường được xác định với $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! 
    }); 
}) 

Để phân tích các thành phần đường dẫn ra khỏi một URL tuyệt đối:

var urlParsingNode = document.createElement('a'); 
urlParsingNode.href = next; // say, next = 'http://www.abc.com/foo?name=joe 
console.log(urlParsingNode.pathname) // returns "/foo" 
+0

nếu có tham số truy vấn trong url ... làm cách nào để xác định bộ định tuyến nào được gọi là – niran

+0

@niran - Tôi đã cập nhật câu trả lời cho bạn. Hãy xem. – tamakisquare

+3

Tính năng này hoạt động như thế nào cho các tuyến đường có thông số? như/article /: articleId? – mkhatib

7

Kể từ phiên bản 1.3.0 bạn thực sự có thể sử dụng vừa được giới thiệu preventDefault -method. Với nó, bạn có thể hủy bỏ việc thay đổi tuyến đường hiện tại và sau đó áp dụng tùy chỉnh của riêng bạn chuyển hướng như thể hiện trong github-issue này:


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

tôi thực hiện phương pháp này trong dự án riêng của tôi và nó hoạt động hoàn hảo. Hy vọng nó sẽ giúp bất cứ ai khác tình cờ gặp nó.