Search code examples
knockout.jsknockout-2.0single-page-applicationdurandalhottowel

Using Durandal Composition manually


I have an empty container in my html like:

<div id='workspace-container'></div>

I want to create my model manually and compose it with some view, then inject the result into the #workspace-container using javascript like:

var myViewModel = new ViewModel (param1, param2);
// Doing some actions on myViewModel

// Some MAGIC here:
composition.compose(myViewModel, myView, '#workspace-container');

What is the api to do such magic!?

Update1: In fact I need manual binding for a reason. I want to be able to select what to inject. Something like:

if (condition1) {
    var myViewModel1 = new ViewModel1 (param1, param2);
    composition.compose(myViewModel1, myView1, '#workspace-container');
}
else if (condition2) {
    var myViewModel2 = new ViewModel2 (param1, param2);
    composition.compose(myViewModel2, myView2, '#workspace-container');
}
...

Solution

  • The way you're describing is possible by creating a property on your main view model that exposes the view model that you are trying to compose. If you don't specify the view manually, the view locator will be used to find the view for the specified view model.

    Then the binding looks like this:

    //in your view
    <div id='workspace-container` data-bind='compose: workspaceContainer'></div>
    
    //in your main view model expose the sub view model property property
    var self = this;
    this.workspaceContainer = ko.observable();
    
    //later
    var v, vm;
    if ('condition1') {
        system.acquire("viewModels/viewModelForCondition1").done(function (modelCtor) {
            v = "views/viewModelForCondition1.html";
            vm = new modelCtor(param1, param2);
            self.workspaceContainer({ view: v, model: vm });
        });
    } else {
        system.acquire("viewModels/viewModelForCondition2").done(function (modelCtor) {
            v = "views/viewModelForCondition2.html";
            vm = new modelCtor(param1, param2);
            self.workspaceContainer({ view: v, model: vm });
        });
    }
    ...
    

    Couple of notes:

    • the compose binding will recognize or respect subsequent changes to the workspaceContainer property.
    • it is important for your view model module to return a constructor function in order for this to work properly.

    See the section Composing Explicit Models and Views in this link for more information: http://durandaljs.com/documentation/Using-Composition/

    This code is tested using a pre-release version of Durandal 2.0. If there are issues, let me know, and I'll correct them.