如何在 ui-router 解析器中重定向?

Posted

技术标签:

【中文标题】如何在 ui-router 解析器中重定向?【英文标题】:How to redirect in a ui-router resolver? 【发布时间】:2015-06-30 21:45:37 【问题描述】:

我正在尝试在 ui-router 解析器中进行重定向,并想知道是否有办法在路由器解析器中重新路由。目前这并不像人们想象的那样工作。

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

如何在解析器中正确重定向?

我的临时黑客是这样的,但我对此并不满意。

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

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

【问题讨论】:

我不确定在解析器中重定向,但如果您想要检查用户是否登录,也许您可​​以使用$stateChangeStart 事件来代替。 @FranDios 在解析器中使用登录检查的原因是我们不必在 statechange 中指定不检查哪个 url。 【参考方案1】:

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

然后ui-router总是广播“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)
  
)

【讨论】:

这应该是正确的答案。 resolver 只能用于解决/拒绝依赖关系。 不@Kunal。虽然这可能更“惯用”,但它存在将路由逻辑拆分到各处的问题。从实际的角度来看,情况更糟。考虑可维护性。 @bwest87 如果错误处理程序依赖于您尝试访问的页面怎么办?这就是我正在谈论的用例。在我正在开发的应用程序中,这会导致分布式逻辑。这很糟糕,因为它是一个非常大的应用程序 @UAvalos 此答案允许您将任意选项传递给错误处理程序。在我的示例代码中,我传入了一个redirectTo: state 对象,它告诉错误处理程序确切地进入哪个状态。因此,它具有取决于您尝试访问的页面的错误处理程序逻辑,正如您所描述的那样。如果你需要更多,比如说......你想传递一个自定义消息,那么我建议你也传递它,比如redirectTo: state, message: customMessage,你的错误处理程序可以处理这个问题。基础设施是灵活的。还是我不理解你的问题? 如何使用新的 API 做到这一点? $state.go 似乎在 $transitions.onError 处理程序中不起作用【参考方案2】:

您可以从您的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。看起来只有将它放在超时函数中才有效。

【讨论】:

这种方法似乎没有重定向 @EdgarMartinez 好的,我用 plunkr 玩了一会儿,发现重定向只有放在一些异步函数中才有效(超时是最简单的选项)。请检查它是否适合您。 好的,我认为我的解决方案就目前而言就是这样 您知道为什么必须这样做吗?我不明白为什么我们必须使用超时来完成这项工作。我有同样的问题,为了解决它,我必须使用超时。 我认为你最好只保留$timeoutvar deferred = $q.defer(); if (true) $timeout(function() $state.go('error'); deferred.reject(); ); else deferred.resolve(); return deferred.promise;中的重定向【参考方案3】:

我用这个

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

【讨论】:

它确实有效!它非常干净和简单!为什么有人在上面标记负分? 我喜欢这个解决方案!非常清晰易懂! @Benson,你摇滚!我会将此答案标记为已接受 执行此操作时,我的控制台中出现“ransition Rejection($id: 0 type: 2, message: the transition has been supersed by a different transition, detail:...." 错误。它做我想要的,但错误消息。【参考方案4】:

这是我实际做的,我找不到更好的解决方案

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

【讨论】:

【参考方案5】:

我认为一个更简洁的答案是像这样返回一个已经被拒绝的承诺:

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

【讨论】:

奇怪,它对我有用。也许它在不同的 AngularJS/UI-Router 版本中发生了变化? 我还没有尝试过,但根据这个应该是公认的答案:github.com/angular-ui/ui-router/issues/… @DanKing 这正是我的回答。 $state.go 然后返回一个被拒绝的承诺$q.reject()。感谢您提供额外的信息! 是的,这就是我的意思——对不起@Tibo。我想说的是您的答案应该是公认的答案,因为它与我提供的链接相同。【参考方案6】:

您可以在 redirectTo 配置中使用解析器承诺

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

【讨论】:

【参考方案7】:

为此使用解决方案对我来说并不奏效。我调整了this post 的逻辑,在状态对象的data 属性上执行重定向功能。然后,您可以从模块的运行块中访问 $rootScope 上的 $stateChangeStart 事件,并使用注入器服务的调用方法根据您指定的条件更改状态。跨模块也能很好地工作。

【讨论】:

以上是关于如何在 ui-router 解析器中重定向?的主要内容,如果未能解决你的问题,请参考以下文章

在每个页面中使用嵌套视图时如何使用 ui-router 进行页面重定向?

如何在PHP中重定向到同一页面

如何在NGINX中重定向一个网址

如何在 React 中重定向

如何在 laravel jetstream 中重定向?

如何在点击时在 React 中重定向?