0
votes

I am trying to initialize a child router to build sub navigation for the customer section of my application.

The url i am trying to configure is:

#customer/1/orders/1

I defined a route to get to the customer view in my shell.js

define(['plugins/router', 'durandal/app'], function (router, app) {
    return {
        router: router, 
        activate: function () {
            router.map([
                { route: 'customer/:id*splat', moduleId: 'customer/customer' }
            ]).buildNavigationModel();

            return router.activate();
        }
    };
});

I created a customer view that contains sub navigation for the customer section. The navigation will use the customer id that was in the route. This view doesnt really do anything except show customer sub-navigation. I created a child router in this view.

define(['plugins/router', 'knockout'], function (router, ko) {
    var childRouter = router.createChildRouter()
        .makeRelative({
            moduleId: 'customer',
            fromParent: true
        }).map([
            { route: 'orders/:orderId', moduleId: 'orders' }
        ]).buildNavigationModel();

    var activate = function(id) {

    };

    return {
        router: childRouter,
        activate: activate
    };
});

My problem is that I can't seem to get the routing to work when I have a parameter in my parent router. The customer view gets routed to but the orders view doesn't. I will end up having more sub views under the customer section.

2
@blazkovicz I ended up having to add a custom hash to each of my routes hash: '#customer/' + id + '/orders' where id is the parameter in my activate function. Not sure if this is the best or correct method.Justin

2 Answers

3
votes

I came across this question looking for the same answer. I did manage to get it working just fine with my parameterized route. My childRouter is second level and I'm also using {pushState: true} so have no #(hashes) in my hashes :) so you'll need to add some if you're not using pushState. It looks like this:

Folder structure looks like this:

app
 |
 |--users
     |
     |--profile
     |    |
     |    |--activity.html
     |    |--activity.js
     |    |--articles.html
     |    |--articles.js
     |    |--tags.html
     |    |--tags.js
     |
     |--index.html
     |--indexjs
     |--profile.html
     |--profile.js

Splat route in the top level router:

{ route: 'users/:userId/:slug*details', title: 'User',      moduleId: 'users/profile',      nav: false }

profile.js looks like this:

define(['plugins/router', 'plugins/http', 'durandal/app', 'jquery', 'knockout', 'timeago', 'bootstrap'], function (router, http, app, $, ko) {
    var childRouter = router.createChildRouter();

    var userProfile = function(user) {
        $.extend(this, user);
    };

    var userProfileViewModel = function () {
        var self = this;
        self.userProfile = ko.observable();
        self.router = childRouter;
        self.activate = function () {
            var userId = router.activeInstruction().params[0];
            var slug = router.activeInstruction().params[1];
            var userRoute = '/users/' + userId + '/' + slug;
            self.router.reset();
            self.router
                .makeRelative({
                    moduleId: 'users/profile',
                    route: 'users/:userId/:slug'
                })
                .map([
                { route: '', moduleId: 'articles', title: 'articles', nav: false, hash: userRoute + '/articles' },
                { route: 'articles', moduleId: 'articles', title: 'articles', nav: true, hash: userRoute + '/articles' },
                { route: 'tags', moduleId: 'tags', title: 'tags', nav: true, hash: userRoute + '/tags' },
                { route: 'activity', moduleId: 'activity', title: 'activity', nav: true, hash: userRoute + '/activity' }
                ]).buildNavigationModel();
            return self.loadUserProfile(userId);
        };
        self.loadUserProfile = function(userId) {
            var url = '/api/users/profile/' + userId;
            return http.jsonp(url).then(function(response) {
                self.userProfile(new userProfile(response));
            });
        };
    };
    return userProfileViewModel;
});

Note also that I'm returning a constructor function here, not an object since in my case I don't want a singleton for this view.

Hope that helps anyone with the same question

0
votes

I'd keep it simple and start with some static routes at the top level

router.map([
    { route: 'customer/:id', moduleId: 'customer/customer' },
    { route: 'customer/:id/orders/:id', moduleId: 'customer/orders' },
    { route: 'customer/:id/xxx/:id', moduleId: 'customer/xxx' }
]).buildNavigationModel();

In order to have full life cycle control for each customer (order, xxx, etc.) instance return a constructor function instead of a singleton.

define(['knockout'], function (ko) {

    var ctor = function(){
       ...
    };

    //this runs on every instance
    ctor.prototype.activate = function(id) {  // or function(orderId, xxxID)

    };

    return ctor;
});

More info singleton vs constructor: http://durandaljs.com/documentation/Creating-A-Module.html