Durandal Subrouting (Hottowel)

2019-01-21 18:10发布

问题:

Basically, I am trying to create a menu inside a menu. So, within a main menu route, there will be a vertical menu with another set of routes. When clicking on the submenu routes, only a part of the page gets updated, and the vertical menu does not reload. I am guessing it would be similar to this KO fiddle http://jsfiddle.net/dPCjM/, but there would need to another set of "ghost" KO directives in a main route view:

 <!--ko compose: {model: router.activeItem, 
            afterCompose: router.afterCompose, 
            transition: 'entrance'} -->
 <!--/ko-->

and some other configs on the durandal router...

EDIT: And to clarify, I am not trying to create a dropdown in one of the main menu items. I am trying to create a menu inside one of the views. Basically a durandal app inside a durandal app :)

IFRAMES?? :))))))))))

回答1:

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.



回答2:

Just as a heads up to those interested, the upcoming Durandal js 2.0 release has baked in features for deep linking which greatly simplifies things over rolling your own deep linking based upon Evan's excellent example.

Check out the Knockout sample to see it in action, which you can grab from the latest binaries via the Durandal js github project.

Of note, it is a substantial departure from the previous version of Durandal so you'll have to do some modification to the original HotTowel template to support it as there are numerous breaking changes.