I have a Durandal application, and I use router.mapUnknownRoutes
to display a user-friendly error page if the URL does not correspond to a known route. This works fine -- if I go to, say /foo
, and that doesn't match a route, then the module specified by mapUnknownRoutes
is correctly displayed.
However I cannot find any way to display that same error page when I have a parameterised route, and the parameter does not match anything on the backend.
For example, say I have a route like people/:slug
where the corresponding module's activate
method looks like this:
this.activate = function (slug) {
dataService.load(slug).then(function () {
// ... set observables used by view ...
});
};
If I go to, say /people/foo
, then the result depends on whether dataService.load('foo')
returns data or an error:
- If
foo
exists on the backend then no problem - the observables are set and the composition continues. - If
foo
doesn't exist, then the error is thrown (because there is nocatch
). This results in an unhandled error which causes the navigation to be cancelled and the router to stop working.
I know that I can return false
from canActivate
and the navigation will be cancelled in a cleaner way without borking the router. However this isn't what I want; I want an invalid URL to tell the user that something went wrong.
I know that I can return { redirect: 'not-found' }
or something similar from canActivate
. However this is terrible because it breaks the back button -- after the redirect happens, if the user presses back they go back to /people/foo
which causes another error and therefore another redirect back to not-found
.
I've tried a few different approaches, mostly involving adding a catch
call to the promise definition:
this.activate = function (slug) {
dataService.load(slug).then(function () {
// ... set observables used by view ...
}).catch(function (err) {
// ... do something to indicate the error ...
});
};
- Can the
activate
(orcanActivate
) notify the router that the route is in fact invalid, just as though it never matched in the first place? - Can the
activate
(orcanActivate
) issue arewrite
(as opposed to aredirect
) so that the router will display a different module without changing the URL? - Can I directly
compose
some other module in place of the current module (and cancel the current module's composition)?
I've also tried an empty catch
block, which swallows the error (and I can add a toast here to notify the user, which is better than nothing). However this causes a lot of binding errors because the observables expected by the view are never set. Potentially I can wrap the whole view in an if
binding to prevent the errors, but this results in a blank page rather than an error message; or I have to put the error message into every single view that might fail to retrieve its data. Either way this is view pollution and not DRY because I should write the "not found" error message only once.
I just want an invalid URL (specifically a URL that matches a route but contains an invalid parameter value) to display a page that says "page not found". Surely this is something that other people want as well? Is there any way to achieve this?