如何在 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 玩了一会儿,发现重定向只有放在一些异步函数中才有效(超时是最简单的选项)。请检查它是否适合您。 好的,我认为我的解决方案就目前而言就是这样 您知道为什么必须这样做吗?我不明白为什么我们必须使用超时来完成这项工作。我有同样的问题,为了解决它,我必须使用超时。 我认为你最好只保留$timeout
var 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 解析器中重定向?的主要内容,如果未能解决你的问题,请参考以下文章