EDIT
As of Durandal.js 2.0 the Router pluggin now has a built in Child Routers which allows for deeplinking out of the box.
/Edit
The below answer perstains to durandal 1.2
The durandal router plugin is a wrapper around sammyjs.
The router plugin allows you to control the browser history stack and also gives your spa the ability to link into pages w/in your spa.
Its pretty easy to get it to do linking 1 level deep where you have 1 main menu and pages that swap in and out. But what if you wanted to have a sub menu w/in the main menu and provide deep linking.
When the router is queued to swap views the viewmodel activator first checks if the request is for the same page in your viewmodel. If it is the same view then you can cancel the route before it happens. By canceling the route when it calls the same page this allows you to take the route parameters and handle the subroute yourself.
The method that checks to see if its calling the same page is in the viewmodel called areSameItem
. You can override this method inside your main viewmodel by calling:
return App = {
router: router,
subPage: ko.observable('defaultSubPage'),
activate: function () {
router.activeItem.settings.areSameItem = function (currentItem, newItem, data) {
if (currentItem != newItem) { return false; }
else { App.subPage(convertSplatToModuleId(data.splat)); return true; }
}
}
}
Of course this is inside an amd module and router
is the durandal router plugin. convertSplatToModuleId
is a function that takes the splat
property, which is the route values, and converts it to the module of the sub page you wish to show.
So, that part was easy but there is 1 more thing that needs to be done.
<div data-bind="compose: { model: subPage, afterCompose: router.afterCompose }"></div>
Your binding for the container of the subPages needs to call router.afterCompose
because this is what tells the router that the route has been completed and its ready to handle new routes.
This is not an easy task to explain. So, I created an example and pushed it to github here.