Take the 2-minute tour ×

I am working on a SPA that I would like to use multiple master views. Here is my use case:

I have a user that has a profile page. Within that profile page I would like to be able to display a couple of different views, ie. details, works, contact info, etc. I need to be able to deep link to each of these views. Each of these views must display the basic user data from the master layout view.

It is my understanding that I should be using compose for this and I have a bit of code that seems to work, however, I want to be able to pass data from the "secondary shell" down to the actual sub view. It seems that the splat data is not passed along to the activate method of the sub viewmodel.

In my "master" viewmodel I have created an observable called activeView that contains a string corresponding to a sub viewmodel (viewmodels/user/details). I then have a knockout statement that is as follows:

<!-- ko compose: {
    model: activeView(),        
    activate: true

How can I pass data to the sub view? Or is there a better way to do this?

Thanks in advance!

share|improve this question
add comment

2 Answers

According to me, ko.compose is not so dynamic and seems to work like Razor's layout. With durandal it's better to make separate views as you can and then, link them to the router. I'm working with John Papa's Hot-Towel template; My proposal concerns passing data (more than id) with durandal router and knockout.

When initializing your app (shell.js, main.js, ...) map your routes somewhere (shell.js or main.js) with settings for eventually filtering. For routes which will transport data, built them with the (:id) proposal

router.mapRoute('view/:id', moduleId, 'Customer Details', false);

Where and when some routes needed You can have a look to Joseph Gabriel's solution (http://stackoverflow.com/a/16036439/2198331) to filter your routes for use where and when you need them. After you filter the routes, you can hack routeInfo to transport your parameters (strings or objects like selectedItem).

arearoutes = ko.utils.arrayFilter(router.visibleRoutes(), function (route) {
              // mgpe has been set at app init
                return route.settings.mgpe === 112; 

extend your routeInfo from filter's results with the data you want to transport

     ar.myItem = mydata; // or vm.selectedItem(); DEPARTURE LUGGAGE
}, areaRoutes);

Your (myItem) is now attached to these routes as so as you like This or these route(s) will carry your data with them and will never lost it unless you updated the same object of the router (myItem)

function activate(adata){
       vm.arrivalData(adata.routeInfo.myItem);  // ARRIVAL LUGGAGE are here

a route can carry nested routes Useful for nested context like nested menus; you can play with children routes by preparing the travel when a parent route is active :

router.activeItem.settings.areSameItem = function (currentItem, newItem, activationData) {
   mybag = activationData.routeInfo; // TRAVEL (current) LUGGAGE are present here

N.B. : before use this work-around you have to consider the security issue and as I'm new to durandal I don't know if this will not bring serious consequences at the router's route life-cycle. Also be aware with object's names as its stay permanently during the router's route living.

share|improve this answer
add comment

How about you create a user object and require it within each of your viewmodels? The easy thing would be to attach it to the app (i.e. app.user = ) Changes made to any of the observables in said user object will update to each of the views and viewmodels within your SPA.

That way you're leveraging the capabilities of the knockout library's sub/pub

share|improve this answer
The application that I wrote requires this behavior on more than just user objects. Durandal 2.0 introduced "child routers" which essentially allows users to create multiple nested shells with deep linking support. Naturally child routers were the way to go for me. –  mcottingham Jan 16 at 14:13
Understood, these two ideas (routing and an application datacontext) work together. You're building a SPA which initializes itself on the client side and rarely does a full post back. The value you get is being able to approach your development simliar to a desktop app rather than the traditional web app that uses full post backs. This means you can create a datacontext which saves objects into memory. That way you don't have to pass objects between views, you can just maintain a global datacontext and pass around an ID within the route using parameters rather than entire objects. –  onzur Jan 17 at 14:29
add comment

Your Answer


