2015-04-22 3 views
39

Sto provando a reindirizzare all'interno di una risoluzione del router e volevo sapere se c'è un modo per reindirizzare in un resolver router. Attualmente questo non funziona come si potrebbe pensare.Come reindirizzare in una risoluzione del router?

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

come si fa a reindirizzamento in un resolver correttamente?

Il mio mod di risposta è questo ma non mi sento a mio agio.

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

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

Non sono sicuro del reindirizzamento all'interno di un resolver, ma se si desidera verificare se l'utente è connesso o meno, è possibile utilizzare l'evento '$ stateChangeStart'. –

+1

@FranDios La ragione per utilizzare il registro di controllo in resolver è che non è necessario specificare in statechange quale URL non controllare. – Marcio

risposta

37

È possibile restituire una promessa da parte vostra funzione resolver che indicherà se continuare la navigazione verso lo stato o meno. Se si decide di spostarsi da qualche altra parte - respingere la promessa e specificare il corretto stato:

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: codice aggiornato e aggiunto plunkr. Sembra che funzioni solo se lo inserisci in una funzione di timeout.

+0

Questo approccio non sembra reindirizzare –

+3

@EdgarMartinez Ok, ho giocato un po 'con plunkr e ho capito che il reindirizzamento funziona solo se è inserito all'interno di una funzione asincrona (timeout è l'opzione più semplice). Si prega di verificare se funziona per voi. –

+1

OK Penso che la mia soluzione fino ad ora come sopra descritta sia proprio così come sarà per il momento –

43

La risposta di Yauheni funziona, ma per aggirare la strana funzione di timeout, è possibile rifiutare la promessa e rilevarla nell'evento $ stateChangeError, quindi eseguire il reindirizzamento. In questo modo ...

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

E poi ui-router trasmette sempre "stateChangeError", in modo da poter fare qualcosa di simile ..

$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

Questa dovrebbe essere la risposta corretta. Il 'resolver' dovrebbe essere usato solo per risolvere/rifiutare le dipendenze. – Kunal

+7

nah @Kunal. Mentre questo può essere più "idiomatico", ha un problema di dividere la logica di routing ovunque. Questo è peggio dal punto di vista pratico. Pensa alla manutenibilità. –

+0

@UAvalos La logica di routing si trova esattamente nello stesso punto in cui si trova nella risposta accettata (che è esattamente 2). Hai un file di stati e un catcher di errori per i reindirizzamenti. Questa risposta dice semplicemente "hey, stai già reindirizzando 404 e così via nel gestore degli errori, quindi reindirizziamo anche gli errori di autenticazione nello stesso punto". In entrambi i casi, "if cantAuth -> go" somewhere "* intention * si trova nello stesso posto (il resolver) .Questa risposta lo pulisce un po 'rimuovendo un timeout non necessario. – bwest87

1

Questo è quello che in realtà fare, e posso' t trovare una soluzione migliore

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

io uso questo

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

Funziona! Ed è molto pulito e semplice! Perché qualcuno ha segnato un punteggio negativo su di esso? – Benson

+0

Amo questa soluzione! molto chiaro e facile da capire! @Benson, tu rock! Segnerei questa risposta come accettata – Nat

0

È possibile utilizzare le promesse resolver dal con la configurazione RedirectTo

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

Credo che una risposta molto più pulito è quello di restituire una promessa già respinto in questo modo:

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

0

Utilizzando risolve per questo non ha funzionato abbastanza per me. Ho adattato la logica di this post per eseguire una funzione di reindirizzamento sulla proprietà data dell'oggetto stato. È quindi possibile toccare l'evento $ stateChangeStart su $ rootScope dal blocco di esecuzione del modulo e utilizzare il metodo invoke del servizio injector per modificare lo stato in base alle condizioni specificate. Funziona bene anche tra i moduli.