2015-04-22 5 views
39

Ich versuche, in einem UI-Router Auflösung umzulenken und wollte wissen, ob es eine Möglichkeit gibt, in einem Router Resolver umzuleiten. Derzeit funktioniert das nicht so, wie man denken würde.Wie umleiten in einem UI-Router lösen?

resolver(auth, $state){ 
    if(!auth.isLoggedIn()){ 
     $state.go('noLoggedInPath'); 
    } 
} 

Wie funktioniert eine Umleitung in einem richtig Resolver?

Mein Temp Hack ist dies, aber ich bin nicht damit zufrieden.

resolver(auth, $state, $timeout){ 
    if(!auth.isLoggedIn()){ 
     $timeout(function() { 

      $state.go('noLoggedInPath'); 
     }, 0); 
    } 
} 
+0

Ich bin mir nicht sicher, in einem Resolver umzuleiten, aber wenn Sie überprüfen möchten, ob der Benutzer angemeldet ist oder nicht, können Sie vielleicht stattdessen das Ereignis '$ stateChangeStart' verwenden. –

+1

@FranDios Der Grund für die Verwendung des Einlogg-Check-In-Resolvers ist, dass wir in Statechange nicht angeben müssen, welche URL nicht geprüft werden soll. – Marcio

Antwort

37

Sie können ein Versprechen aus Ihrer resolver Funktion zurück, die auf den Zustand der Navigation fortzusetzen oder nicht an, ob. Wenn Sie sich entscheiden, woanders zu navigieren - das Versprechen ablehnen und den ordnungsgemäßen Zustand angeben:

resolver($q, $state, $timeout, auth) { 
    var deferred = $q.defer(); 

    // $timeout is an example; it also can be an xhr request or any other async function 
    $timeout(function() { 
     if (!auth.isLoggedIn()) { 
     // user is not logged, do not proceed 
     // instead, go to a different page 
     $state.go('noLoggedInPath'); 
     deferred.reject(); 
     } else { 
     // everything is fine, proceed 
     deferred.resolve(); 
     } 
    }); 

    return deferred.promise; 
} 

Plunkr here.

UPD: Code aktualisiert und Plunkr hinzugefügt. Sieht so aus, als ob es nur funktioniert, wenn Sie es in eine Timeout-Funktion setzen.

+0

Dieser Ansatz scheint nicht umzuleiten –

+3

@EdgarMartinez Ok, ich spielte ein wenig mit Plunkr und erkannte, dass Redirect funktioniert nur, wenn es innerhalb einer asynchronen Funktion platziert ist (Timeout ist die einfachste Option). Bitte überprüfen Sie, ob es für Sie funktioniert. –

+1

OK Ich denke, dass meine Lösung, so weit wie oben erwähnt, genau so ist, wie es vorläufig sein wird –

43

Yauhenis Antwort funktioniert, aber um die seltsame Timeout-Sache zu umgehen, können Sie das Versprechen ablehnen und das im $ stateChangeError-Ereignis abfangen und dort umleiten. Wie so ...

state('admin', { 
    resolve: { 
    auth: function(UserService, $q, permissionService) { 
    var deferred = $q.defer(); 
    return UserService.load().then(function(user){ 
     if (permissionService.can(user, {goTo: state})) { 
     return deferred.resolve({}); 
     } else { 
     return deferred.reject({redirectTo: 'some_other_state'}); 
     } 
    } 
    } 
}); 

Und dann ui-Router immer sendet "stateChangeError", so dass man etwas tun kann ..

$rootScope.$on('$stateChangeError', function(evt, to, toParams, from, fromParams, error) { 
    if (error.redirectTo) { 
    $state.go(error.redirectTo); 
    } else { 
    $state.go('error', {status: error.status}) 
    } 
}) 
+1

Dies sollte die richtige Antwort sein. Der 'Resolver' sollte nur zum Auflösen/Ablehnen von Abhängigkeiten verwendet werden. – Kunal

+7

nah @Kunal. Obwohl dies "idiomatischer" sein mag, hat es ein Problem, die Routing-Logik überall aufzuteilen. Das ist aus praktischer Sicht schlechter. Denk an Wartbarkeit. –

+0

@UAvalos Die Routing-Logik lebt genau an den gleichen Stellen wie in der akzeptierten Antwort (was genau 2 ist). Sie haben eine Statusdatei und einen Fehler-Catcher für Weiterleitungen. Diese Antwort sagt nur, "hey, du leitest schon 404's und so in den Error-Handler, also laß uns auch Auth-Fehler an derselben Stelle umleiten." In beiden Fällen ist das "if cantAuth -> go" irgendwo "* intention *" an der gleichen Stelle (der Resolver). Diese Antwort räumt nur ein wenig auf, indem es ein nicht benötigtes Timeout entfernt. – bwest87

1

Dies ist, was eigentlich tue ich, und ich kann‘ t finden eine bessere Lösung

resolver($q, $timeout, myService) { 
    if(!areParameterValuesValid() || !isEverythingLogicallyOk()){ 
     var deferred = $q.defer(); 
     $timeout(function() { 
      $state.go('somewhere'); 
      deferred.reject(); 
     }); 
     return deferred.promise; 
    } else { 
     return myService.loadSomething(passingSomeParams); 
    }   
} 
4

ich benutze diese

function Check($state, $q) { 
     var deferred = $q.defer(); 
     if (condition) { 
      deferred.resolve(); 
     } 
     else { 
      deferred.reject(); 
     } 
     return deferred.promise.catch(function() { $state.go('path'); }); 
    } 
+0

Es funktioniert! Und es ist sehr sauber und einfach! Warum hat jemand einen Minuspunkt markiert? – Benson

+0

Ich liebe diese Lösung! sehr klar und leicht zu verstehen! @ Benson, du rockst! Ich würde diese Antwort als akzeptiert markieren – Nat

0

Sie Resolver Versprechungen mit der RedirectTo Konfiguration

redirectTo: function($transition$) { 
     return $transition$.injector().getAsync('isNew').then(function(isNew) { 
     return isNew ? 'estate.edit' : 'estate.view'; 
     }); 
    }, 
1

Ich denke, eine viel saubere Antwort ist ein bereits abgelehnten Versprechen wie so zurückkehren können:

resolver(auth, $state, $q){ 
 
    if(!auth.isLoggedIn()){ 
 
     $state.go('noLoggedInPath'); 
 
     
 
     // Return rejected promise 
 
     return $q.reject(); 
 
    } 
 
    return true; 
 
}

0

Mit Entschlüssen Dafür hat es für mich nicht geklappt. Ich habe die Logik von this post angepasst, um eine Umleitungsfunktion für die Eigenschaft data des Zustandsobjekts auszuführen. Sie können dann das $ stateChangeStart-Ereignis in $ rootScope im run-Block des Moduls antippen und die invoke-Methode des Injektor-Services verwenden, um den Status basierend auf den von Ihnen angegebenen Bedingungen zu ändern. Funktioniert auch gut über Module hinweg.