Multiple levels of routing in Durandal
Asked Answered
P

4

9

I am looking at the Durandal samples trying to understand how routing works.

The shell.js specifies these routes:

{ route: ['', 'knockout-samples*details'], moduleId: 'ko/index', title: 'Details...', nav: true, hash: '#knockout-samples' },
{ route: 'view-composition',moduleId: 'viewComposition/index',  title: ...

under knockout-samples:

{ route: '', moduleId: 'helloWorld/index', title: 'Hello World', type: 'intro' },
{ route: 'helloWorld', moduleId: 'helloWorld/index', title: 'Hello World', type: intro', nav: true},

What I am trying to achieve is having another hierarchy under helloWorld. Something like this: enter image description here

I tried this but no luck:

{ route: '', moduleId: 'helloWorld/index', title: 'Hello World', type: 'intro' },
{ route: 'helloWorld*details', moduleId: 'helloWorld/index', title: 'Hello World',           type: 'intro',      nav: true, hash:'#knockout-samples/helloWorld'}

However, this is not working.

Does Durandal routing not support this level of navigation?

Puttee answered 30/8, 2013 at 9:53 Comment(0)
Y
8

When creating a 'grandchild' or 'great grandchild' or deeper child router, the trick is to reference the relative parent router, not the root router. To get a reference to the parent router, add the module that contains the parent router as a dependency to your 'grandchild' module. You can nest routers like this indefinitely. For example:

myModuleWithChildRouter.js

define(['plugins/router'],  //reference to durandal root router
    function(router) {         

           var _childRouter = router.createChildRouter();

          return { myNewChildRouter: _childRouter}
}

myModuleWithGrandchildRouter.js

define(['myModuleWithChildRouter'],  //reference to module with child router
    function(childRouterModule) {        

           var _grandChildRouter = childRouterModule.myNewChildRouter.createChildRouter();
          .....

}

Hope that helps!

Yawning answered 7/10, 2013 at 12:55 Comment(1)
Does anyone have a full example of this working. I am having a problem with the grandchild routes using this pattern.Plerre
P
2

To get more than one navigation level I'm doing this:

The only accesible router is the root router so to have acces to the child routers, everytime that I'm creating a child router, i store it on a module. Then, when i want to create another level, I get the child router from the module and call createChildRouter.

define([], function () {
    return {
        root: null,
        level1: null,
        level2: null
    };
});

define(['plugins/router', 'routers'], function (router, routerContainer) {
    var childRouter = router.createChildRouter()
        .makeRelative({
            moduleId: 'viewmodels/companyplussplat',
            //fromParent: true
            route: 'company'
        }).map([
            { route: 'order/:orderID', moduleId: 'orderdetail', title: 'Order', nav: false },
            { route: 'order/:orderID*details', moduleId: 'orderdetailplussplat', title: 'Order plus splat', nav: false }
        ]).buildNavigationModel();

    routerContainer.level1 = childRouter;

    return {
        activate: function () {
            console.log("Activating company plus splat");
        },
        deactivate: function () {
            console.log("Deactivating company plus splat");
        },
        router: childRouter
    };
});

define(['plugins/router', 'routers'], function (router, routerContainer) {
    //debugger;
    var childRouter = routerContainer.level1.createChildRouter()
        .makeRelative({
            moduleId: 'orderteailplussplat',
            //fromParent: true
            route: 'company/order/:orderID'
        }).map([
            { route: 'orderline/:orderlineID', moduleId: 'orderlinedetail', title: 'Order line detail', nav: false },
        ]).buildNavigationModel();

    routerContainer.level2 = childRouter;

    return {
        activate: function (orderID) {
            console.log('Activating order detail for: '+ orderID +' plus splat');
        },
        deactivate: function () {
            console.log('Deactivating order detail plus splat');
        },
        router: childRouter
    };
});

I hope this will help you.

Parlando answered 30/8, 2013 at 11:48 Comment(3)
+1 This looks promissing, will give it a try. I just updated my post with a picture showing what I need to acheive.Puttee
@Julián I have used you code which works where there is only 1 node. But if I add a second route for the lowest level, it does not navigate to that view. Does it work with your code?Ranna
Hello, I'll test it and I will tell you the result tomorrow.Teat
H
2

I added the child as a reference to the parent router itself. Maybe a bit sneaky, but working happily:

Top level router

define(["plugins/router"], function (router) {
    // create the constructor
    var ctor = function() {
    };

    ko.utils.extend(ctor.prototype, {
        activate: function () {
            //var self = this;
            var map = router.makeRelative({ moduleId: "viewmodels" }).map([
                { route: "", moduleId: "index", title: "Overview", nav: true, hash: "#/", enabled: true },
                { route: "data*details", moduleId: "data/shell", title: "Data Loading", nav: true, hash: "#/data", enabled: false },
                { route: "reporting*details", moduleId: "reporting/shell", title: "Reporting", nav: true, hash: "#/reporting", enabled: true },
                { route: "query*details", moduleId: "query/shell", title: "Query", nav: true, hash: "#/query", enabled: true },
                { route: "login", moduleId: "login", title: "Login", hash: "#/login", state: "out" }
            ]);

            return map.buildNavigationModel()
                .mapUnknownRoutes("404")
                .activate();
        });

    });

    return ctor;
});

Child router

define(["plugins/router"], function (router) {
    var childRouter = router.createChildRouter()
            .makeRelative({
                moduleId: "viewmodels/reporting",
                fromParent: true
            }).map([
                { route: "", moduleId: "index", title: "Reporting", nav: false, hash: "#/reporting" },
                { route: "standard", moduleId: "standard", title: "Standard Reports", nav: true, hash: "#/reporting/standard" },
                { route: "alert*details", moduleId: "alert/shell", title: "Alerts", nav: true, hash: "#/reporting/alert" }
            ]).buildNavigationModel();

    // for alerts
    router.child = childRouter;

    var vm = {
        router: childRouter
    };

    return vm;
});

Grandchild router

define(["plugins/router"], function (router) {
    var grandchildRouter = router.child.createChildRouter()
        .makeRelative({
            moduleId: "viewmodels/reporting/alert",
            fromParent: true
        }).map([
            { route: "", moduleId: "index", title: "Alerts", hash: "#/reporting/alert" },
            { route: ":id", moduleId: "case", title: "Alert Details", hash: "#/reporting/alert" }
        ]).buildNavigationModel();

    var vm = {
        router: grandchildRouter
    };

    return vm;
});

Hope that helps.

Heideheidegger answered 20/1, 2015 at 13:52 Comment(1)
I am not sure this is the recommended approach but it worked for mePronty
D
0

If you are using durandal 2.0 you can set up the child router. This will allow you to create a new router under the hello world that you can chain on additional info for for sub views in your view. You can look these up on the docs but make sure you set up that router within the view so when you hit a route like

 #helloworld/subview

you have already activated helloworld

Doe answered 30/8, 2013 at 11:22 Comment(1)
Thank you. I already did this for the navigation level. As I mentioned in my question, I am having issues defining a second level of navigation :)Puttee

© 2022 - 2024 — McMap. All rights reserved.