2015-04-22 1 views
39

Я пытаюсь перенаправить внутри решения ui-router и хотел узнать, есть ли способ перенаправления в маршрутизаторе. В настоящее время это не работает, как можно было бы подумать.Как перенаправить решение ui-router?

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

Как переадресации в распознавателе правильно?

Мой временный взлом - это, но мне это не удобно.

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

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

Я не уверен в перенаправлении внутри распознавателя, но если вы хотите проверить, вошел ли пользователь в систему или нет, возможно, вы можете использовать событие '$ stateChangeStart'. –

+1

@FranDios Причина использования входа в систему для регистрации в resolver заключается в том, что нам не нужно указывать в statechange, который не должен проверять. – Marcio

ответ

37

Вы можете вернуть обещание из вашей resolver функции, которая будет указывать, следует ли продолжать навигацию к государству или нет. Если вы решили перейти куда-нибудь еще - отклонить обещание и указать надлежащее состояние:

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: обновленный код и добавленный plunkr. Похоже, это работает, только если вы поместили его в функцию тайм-аута.

+0

Этот подход не перенаправляет –

+3

@ EdgarMartinez Хорошо, я немного поиграл с plunkr и понял, что перенаправление работает только в том случае, если оно помещено внутри некоторой асинхронной функции (тайм-аут - это самый простой вариант). Проверьте, работает ли он на вас. –

+1

OK Я думаю, что мое решение, как указано выше, так же, как это будет на данный момент –

43

Ответ Yauheni действительно работает, но чтобы обойти эту странную тайм-аут, вы можете отклонить обещание и поймать это в событии $ stateChangeError и переадресовать туда. Как и ...

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

А затем щ-маршрутизатор всегда передает «stateChangeError», так что вы можете сделать что-то вроде этого ..

$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

Это должен быть правильный ответ. «Resolver» должен использоваться только для разрешения/отклонения зависимостей. – Kunal

+7

nah @ Kunal. Хотя это может быть более «идиоматичным», у него есть проблема разделения логики маршрутизации повсюду. Это хуже с практической точки зрения. Подумайте о поддерживаемости. –

+0

@UAvalos Логика маршрутизации живет точно в тех же местах, что и в принятом ответе (что ровно 2). У вас есть файл состояний и ловушка ошибок для перенаправления. Этот ответ просто говорит: «Эй, вы уже перенаправляете 404 и так в обработчике ошибок, так что давайте также перенаправляем ошибки auth в том же месте». В обоих случаях «if cantAuth -> go« где-то »* намерение * находится в одном месте (резольвер). Этот ответ просто немного очищает его, удаляя ненужный тайм-аут. – bwest87

1

Это то, что я на самом деле, и я могу» т найти лучшее решение

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

Я использую этот

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

Он работает! И это очень просто и чисто! Почему кто-то сделал отметку минус? – Benson

+0

Мне нравится это решение! очень понятный и понятный! @ Бенсон, ты качаешь! Я бы отметил этот ответ как принятый – Nat

0

Вы можете использовать разрешителя обещания от с конфигурацией RedirectTo

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

Я думаю, что гораздо чище ответ вернуть уже отвергнут обещание так:

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

0

Использование раздела решает потому что для меня это не совсем сработало. Я адаптировал логику от this post для выполнения функции перенаправления в свойстве объекта data. Затем вы можете нажать на событие $ stateChangeStart на $ rootScope из блока запуска модуля и использовать метод вызова службы инжектора для изменения состояния на основе заданных условий. Хорошо работает и с модулями.