如何显示"未找到" Durandal

时间:2015-07-29 14:29:38

标签: javascript durandal durandal-2.0 durandal-navigation

我有一个Durandal应用程序,如果URL与已知路由不对应,我使用router.mapUnknownRoutes来显示用户友好的错误页面。这很好 - 如果我去,说/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)。这会导致未处理的错误,导致导航被取消,路由器停止工作。

我知道我可以从false返回canActivate,导航将以更干净的方式取消,而不会堵塞路由器。然而,这不是我想要的;我想要一个无效的URL来告诉用户出现了问题。

我知道我可以从{ redirect: 'not-found' }返回canActivate或类似内容。然而,这很糟糕,因为它打破了后退按钮 - 重定向发生后,如果用户按下它们会返回/people/foo,这会导致另一个错误,因此另一个重定向回not-found

我尝试过几种不同的方法,主要是在承诺定义中添加catch调用:

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(或canActivate)可以发出rewrite(而非redirect),以便路由器在不更改网址的情况下显示不同的模块吗?
  • 我可以直接compose代替当前模块的其他模块(并取消当前模块的构成)吗?

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

我只想要一个无效的URL(特别是一个匹配路由但包含无效参数值的URL)来显示一个页面,其中显示" page not found"。当然这也是其他人想要的东西吗?有没有办法实现这个目标?

2 个答案:

答案 0 :(得分:2)

我认为您应该可以使用activatecanActivate方法中的以下内容。

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

答案 1 :(得分:1)

事实证明,内森的回答虽然不太正确,却让我走上正轨。我所做的似乎有些苛刻,但确实有效。

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

(文档中有一些相关信息,但不是很透彻:http://durandaljs.com/documentation/Using-The-Router.html

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

所以在我的模块中进行数据库查找,在其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,然后在people/joe模块仍然显示时,网址会立即更改回not-found。因为这些都是replace样式导航,如果用户导航回来,他们会转到上一个条目,这是他们在点击断开的链接之前所来自的页面(即后退按钮应该做什么)。 / p>

就像我说的那样,这看起来很丑陋而且我不喜欢URL闪烁,但它似乎是我能做的最好的,大多数人都没有注意到地址栏。

<强> Working repo that demonstrates this solution