1

我有一个 Durandal 应用程序,router.mapUnknownRoutes如果 URL 不对应于已知路由,我会使用它来显示用户友好的错误页面。这很好用——如果我去,说/foo,并且与路线不匹配,那么指定的模块mapUnknownRoutes会正确显示。

但是,当我有参数化路由并且参数与后端的任何内容都不匹配时,我找不到任何方法来显示相同​​的错误页面。

例如,假设我有一条路线people/:slug,对应模块的activate方法如下所示:

this.activate = function (slug) {
    dataService.load(slug).then(function () {
        // ... set observables used by view ...
    });
};

如果我去,说/people/foo,那么结果取决于是dataService.load('foo')返回数据还是错误:

  • 如果foo后端存在,那么没问题 - 设置了可观察对象并继续组合。
  • 如果foo不存在,则抛出错误(因为没有catch)。这会导致未处理的错误,从而导致导航被取消并且路由器停止工作。

我知道我可以返回falsecanActivate并且导航将以更干净的方式取消,而不会破坏路由器。然而,这不是我想要的;我想要一个无效的 URL 来告诉用户出了点问题。

我知道我可以{ redirect: 'not-found' }canActivate. 然而,这很糟糕,因为它破坏了后退按钮——在重定向发生后,如果用户按下后退,他们会返回到/people/foo这会导致另一个错误,因此会再次重定向到not-found.

我尝试了几种不同的方法,主要涉及添加catch对 promise 定义的调用:

this.activate = function (slug) {
    dataService.load(slug).then(function () {
        // ... set observables used by view ...
    }).catch(function (err) {
        // ... do something to indicate the error ...
    });
};
  • activate(或)是否可以canActivate通知路由器该路由实际上是无效的,就好像它从一开始就从未匹配过一样?
  • activate(or )是否可以canActivate发出 a rewrite(而不是 a redirect) 以便路由器在不更改 URL 的情况下显示不同的模块?
  • 我可以直接compose用其他模块代替当前模块(并取消当前模块的组成)吗?

我还尝试了一个空catch块,它吞噬了错误(我可以在这里添加一个 toast 来通知用户,这总比没有好)。然而,这会导致很多绑定错误,因为视图所期望的 observables 从未设置过。可能我可以将整个视图包装在if绑定中以防止错误,但这会导致空白页面而不是错误消息;或者我必须将错误消息放入每个可能无法检索其数据的视图中。无论哪种方式,这都是视图污染而不是 DRY,因为我应该只写一次“未找到”错误消息。

我只想要一个无效的 URL(特别是与路由匹配但包含无效参数值的 URL)来显示一个显示“找不到页面”的页面。当然,这也是其他人想要的吗?有什么办法可以做到这一点?

4

2 回答 2

2

我认为您应该能够使用activateorcanActivate方法中的以下内容。

router.navigate('not-found', {replace: true});

于 2015-07-29T23:51:46.330 回答
2

事实证明,内森的回答虽然不完全正确,但让我走上了正轨。我所做的似乎有点老套,但确实有效。

有两个选项可以传递给router.navigate()-replacetrigger. 传递replace(默认为)使用和(或使用哈希更改事件模拟相同false)在历史插件之间切换。传递(默认为)在实际加载视图(并更改 URL)与仅更改地址栏中的 URL 之间切换。这看起来像我想要的,只是错误的方式 - 我想在不更改 URL 的情况下加载不同的视图。pushStatereplaceStatetriggertrue

(文档中有一些关于此的信息,但不是很详尽:http ://durandaljs.com/documentation/Using-The-Router.html )

我的解决方案是导航到not-found模块并激活它,然后导航回原始 URL 而不触发激活。

因此,在我进行数据库查找的模块中activate,如果找不到记录,我会调用:

router.navigate('not-found?realUrl=' + document.location.pathname + document.location.hash, { replace: true, trigger: true });

(我意识到这trigger: true是多余的,但它使其明确)。

然后在not-found模块中,它activate看起来像:

if (params.realUrl) {
    router.navigate(params.realUrl, { replace: true, trigger: false });
}

用户看到的是,它重定向到,然后在模块仍然显示时not-found?realUrl=people/joe立即将 URL 更改回。因为这些都是样式导航,如果用户导航回来,他们会转到上一个条目,这是他们在单击损坏的链接之前来自的页面(即返回按钮应该做什么)。people/joenot-foundreplace

就像我说的,这看起来很老套,我不喜欢 URL 闪烁,但这似乎是我能做的最好的,大多数人不会注意到地址栏。

演示此解决方案的工作存储库

于 2015-10-07T15:18:16.287 回答