【问题标题】:How to redirect in a ui-router resolver?如何在 ui-router 解析器中重定向?
【发布时间】: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。

标签: angularjs angular-ui-router


【解决方案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 事件,并使用注入器服务的调用方法根据您指定的条件更改状态。跨模块也能很好地工作。

      【讨论】:

        猜你喜欢
        • 2016-02-18
        • 1970-01-01
        • 2017-11-24
        • 1970-01-01
        • 1970-01-01
        • 2018-02-01
        • 2023-03-23
        • 2016-07-02
        • 1970-01-01
        相关资源
        最近更新 更多