21

Il mio problema è in realtà molto simile a quello che si trova qui:

AngularJs - cancel route change event

Insomma, sto usando $ routeChangeStart e cercando di cambiare l'attuale percorso usando $ posizione. Quando lo faccio, la console mi mostra che la pagina originale è ancora carica e viene rapidamente sovrascritta dalla nuova pagina.

La soluzione fornita era quella di utilizzare $ locationChangeStart anziché $ routeChangeStart, che dovrebbe funzionare per impedire il reindirizzamento extra. Sfortunatamente, sto utilizzando ulteriori dati nel $ routeprovider di cui ho bisogno per accedere durante la modifica del percorso (lo uso per monitorare le restrizioni della pagina). Ecco un esempio ...

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

Con $ routeChangeStart, posso utilizzare i parametri "prossimi" "correnti" (vedi AngularJS - $route) come oggetti di recuperare i miei valori 'Accesso'. Con $ locationChangeStart, questi due parametri restituiscono stringhe url, non oggetti. Quindi non sembra esserci alcun modo per recuperare i miei valori di 'accesso'.

C'è un modo per combinare il potere di interruzione del reindirizzamento di $ locationChangeStart con la flessibilità dell'oggetto di $ routeChangeStart per ottenere ciò di cui ho bisogno?

risposta

21

Un approccio che viene in mente sta cercando di utilizzare il parametro risoluzione per questo:

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

prega di notare che non ho ancora testato il codice di cui sopra, ma sto facendo cose simili nei miei progetti.

+0

Ci scusiamo per la risposta tardiva. Quando qualcosa funziona per me, tendo ad emozionarmi e andare avanti. Questo finì per essere una soluzione perfetta per quello che stavo facendo.Nella funzione di caricamento, sono stato in grado di aggiungere cose come '$ http' e' $ posizione' per elaborare ulteriormente le mie richieste. – ThisLanham

+0

Ho dovuto rendere la mia funzione di caricamento più simile a quella di Nick http://stackoverflow.com/a/19482187/1449799 (il rifiuto non funzionava come scritto qui) – Michael

+1

La funzione 'load' dovrebbe essere più simile a questa: 'var deferred = $ q.defer(); if (access) {deferred.resolve(); } else {deferred.reject(); $ Location.url ('/ login'); } return deferred.promise; ' – Clay

3

Bella risposta Marius, mettimi sulla strada giusta. Sto facendo qualcosa di simile per il controllo degli accessi. Questo funziona però ...

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

Quando il percorso/ordini viene cliccato la promessa viene rifiutata (con un pop-up, potrebbe essere dialogo modale) e il percorso non è seguita.

Spero che questo aiuti qualcuno.

+0

qualche consiglio su questo? – Awena

14

Ho affrontato la stessa situazione io stesso e la mia soluzione era allineata con ciò che l'OP intendeva fare.

Uso l'evento $locationChangeStart e il servizio $route. Accedendo a $route.routes, ottengo una sospensione di tutti gli oggetti di percorso definiti con $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! 
    }); 
}) 

per analizzare il componente del percorso di un URL assoluto:

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

cosa succede se c'è un parametro di query nell'URL ... come si identifica il router chiamato – niran

+0

@niran - Ho aggiornato la mia risposta per voi. Guarda. – tamakisquare

+3

Come funziona questo per i percorsi con parametri? come/article /: articleId? – mkhatib

7

Dalla versione 1.3.0 si può effettivamente utilizzare la nuova introduzione preventDefault -Metodo. Con questo è possibile annullare la modifica percorso corrente e quindi applicare le tue reindirizzare come mostrato in questo github-issue:


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

ho implementato questo metodo nel mio progetto e funziona perfettamente. Spero che aiuti chiunque altro che si imbatte in esso.