Knockout.js: Binding Multiple View Models in a View

I came across a situation which needs to render two set of form controls in a view. Both the sets will have controls with the same name. I’m using knockout.js for view model. I tried binding these multiple view models separately using ko.applyBindings(VM1) and ko.applyBindings(VM2) in the same view. But one set of controls worked and the other did not. On searching the web, I found couple of solutions for this problem.

1. Binding View Model Using DOM Element ID:

One of the option is to declare two view models in the same view and then bind them using the ko.applyBindings and adding the DOM element id as the second parameter. For this, we need to wrap the forms (or set of controls) in separate DOM element like <div>. Set unique element id for each <div> enclosing the controls. Use the id as the second parameter for ko.applyBindings and bind the view models separately. Below is the sample. In the sample if you see the control name bookTitle and btnSubmit are in both the forms. Still, using separate view models and binding the view model using DOM-Element id aggregates both the control sets.

<div style="width: 600px; overflow: hidden;">
    <div style="width: 300px; float: left;" id="Form1">
        Book Title:
        <input data-bind="value: bookTitle" /><br />
        Book Price:
        <input data-bind="value: bookPrice" /><br />
        <button data-bind="click: btnSubmit">Submit</button>
    </div>
    <div style="display: table-cell;" id="Form2">
        Author Name:
        <input data-bind="value: authorName" /><br />
        Book Title:
        <input data-bind="value: bookTitle" /><br />
        <button data-bind="click: btnSubmit">Submit</button>
    </div>
</div>
<script src="./knockout-2.2.0.js"></script>
<script type="text/javascript">
    var viewModel_1 = {
        bookTitle: ko.observable("ASP.NET For Everyone"),
        bookPrice: ko.observable("$34.00"),
        btnSubmit: function () { alert(this.bookTitle() + ": " + this.bookPrice()); }
    };

    var viewModel_2 = {
        authorName: ko.observable("Dr. Someone"),
        bookTitle: ko.observable("ASP.NET For Everyone"),
        btnSubmit: function () { alert(this.authorName() + ": " + this.bookTitle()); }
    };

    ko.applyBindings(viewModel_1, document.getElementById("Form1"));
    ko.applyBindings(viewModel_2, document.getElementById("Form2"));
</script>

Knockout-js-Multiple-View-Models

2. Using With-Binding to segregate the controls :

Another option is to use with-binding. In this method, instead of dom-element id, we have to bind the <div> tag enclosing the controls using with. The advantage of with-binding is, we can nest one or more sets of control inside another. Below is the sample. If you see the sample, the <div> is bound using with. Also, there is only one view model. In the view model the two sets of the controls are segregated based on with-binding.

<div style="width: 600px; overflow: hidden;">
    <div style="width: 300px; float: left;" data-bind="with: Book">
        Book Title:
        <input data-bind="value: bookTitle" /><br />
        Book Price:
        <input data-bind="value: bookPrice" /><br />
        <button data-bind="click: btnSubmit">Submit</button>
    </div>
    <div style="display: table-cell;" data-bind="with: Author">
        Author Name:
        <input data-bind="value: authorName" /><br />
        Book Title:
        <input data-bind="value: bookTitle" /><br />
        <button data-bind="click: btnSubmit">Submit</button>
    </div>
</div>
<script src="./knockout-2.2.0.js"></script>
<script type="text/javascript">
    var viewModel = {
        Book: {
            bookTitle: ko.observable("ASP.NET For Everyone"),
            bookPrice: ko.observable("$34.00"),
            btnSubmit: function () { alert(this.bookTitle() + ": " + this.bookPrice()); }
        },
        Author: {
            authorName: ko.observable("Dr. Someone"),
            bookTitle: ko.observable("ASP.NET For Everyone"),
            btnSubmit: function () { alert(this.authorName() + ": " + this.bookTitle()); }
        }
    };

    ko.applyBindings(viewModel);
</script>

Reference: Knockoutjs.com.

Leave your thoughts...