Multiple View Models with Knockout

In a recent project, I was required to create a form for user input in a web page. Each section of the form is distinct and serves a unique purpose, so I chose to use a tabbed layout . The order in which the forms are completed was not a strict requirement, so some visual indication of which sections were completed was also a requirement.

I decided to use Knockout js for the data binding to take advantage its easy data bindings as well as the ko.computed method to determine which sections are complete.  While creating a design for this, it became apparent that each section (tab) should be its own view model. The problem was that there really isn’t any documentation on how to create multiple view models on a single page. There is an obscure reference deep in the Knockout js documentation that does not clearly explain how to do it.

After a bit of googling, I could not find any clear instructions on how to solve the problem; only some single line answers. After getting small hints from several google search results and some trial and error, I was able to come up with a clean solution.

The solution is actually quite simple, but I thought I would share it with since having a clear example would have saved me a lot of time.

The first thing to do is to create your sections on the page with a unique id.

<section class="tab" id="firstSection">
	<h1>First Section</h1>
	<p>First Name: <strong data-bind="text: name"></strong></p>
	<p>First name: <input data-bind="value: name" /></p>

</section>

<section class="tab" id="secondSection">
	<h1>Second Section</h1>
	<p>Second Name: <strong data-bind="text: name"></strong></p>
	<p>Second name: <input data-bind="value: name" /></p>	
</section>

One thing you may notice about this example is that it is using the same variable name called “name” in each section. This is one of the benefits of using multiple view models since those variables are only accessible in the scope of the view model.

Second, you will need to define your view models. There is nothing special about how these are defined for this particular solution.

function firstViewModel() {
	var self = this;
	self.name = ko.observable("Enter Name");			
};

function secondViewModel() {
	var self = this;
	self.name = ko.observable("Enter Name");	
};

Lastly, you will need to apply the bindings for the view models and assign them to the previously defined sections.

ko.applyBindings(new firstViewModel, $("#firstSection")[0]);
ko.applyBindings(new secondViewModel, $("#secondSection")[0]);

Take note of the second parameter passed to the applyBindings method as it does the magic of isolating the view model to a specific element on the page.  I am not sure why this isn’t clearly documented anywhere, but hopefully this post proves useful to anyone that is looking to add support for multiple view models on a single page.

A working demo can be found here

About these ads

25 Responses to “Multiple View Models with Knockout”

  1. Thanks a BILLION.

  2. Thanks for this useful piece of code and enlightenment!

  3. Thanks, that was helpful.

  4. Super!! Very helpful! I just started KO, and this was a major issue for me.
    I put the JS in two different files apart from the HTML, and renamed name to name2 in second file. Your example keeps working with only one ViewModel.

  5. I believe document.getElementById(“firstSection”) will also work instead of $(“#firstSection”)[0] if you don’t have jQuery.

  6. Great one dude.,,

  7. Awesome. Thanks for writing this up. It should be part of core docs.

  8. Brilliant, thanks for taking the time to document this, just what we need, cheers

  9. Excellent! Thanks!

  10. Thank you. I am learning KO and was unsure how to bind multiple view models. Your information was very useful.

  11. Excellent man this is what I was trying to achieving from couple of days ….. Keep sharing

  12. Thank you! I was looking for that!

    “Optionally, you can pass a second parameter to define which part of the document you want to search for data-bind attributes. For example, ko.applyBindings(myViewModel, document.getElementById(‘someElementId’)). This restricts the activation to the element with ID someElementId and its descendants, which is useful if you want to have multiple view models and associate each with a different region of the page.”
    Source: http://knockoutjs.com/documentation/observables.html

  13. You saved me a lot of time, much appreciated!

  14. Dude thanks amazing! Studying knockoutjs and so far im liking it!
    Orlando PHP Development

  15. Clear and complete!
    if everyone would write articles like this, the world would be better :)

  16. Thanks a ton :) I was looking for something of this kind.

  17. very helpful and article to the point.

  18. First, thank you for taking the time to provide this.

    In case anyone else experienced this strange behavior I encountered you may find my experience and solution useful.

    I applied this solution to a kendoDropDownList nested within a kendoTabStrip. Using ko.applyBindings(new firstViewModel, $(“#firstSection”)[0]) correctly bound the data to the kendoDropDownList as expected. However, for some reason when I used [0] it caused the elements comprising my kendoTabStrip to lose their css positioning and become exposed.

    I discovered by using [1] instead of [0] brought the elements back into their proper position.

    On a separate note, the second parameter may be any type of jquery selector returning a single element. So, ko.applyBindings(new firstViewModel, $(“.firstSectionClassName”)[0]); will apply the binding to the first element with a class=”firstSectionClassName”

  19. This breaks in knockout 2.3 and 3.0 sadly… any work arounds?

  20. thanks a lot !!! this saved much time..

  21. Amazing work buddy solved a big problem :-)

  22. Keep working ,fantastic job! dadaadcbdbfg

Trackbacks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: