259

I'm using KnockoutJS and have a main view and view model. I want a dialog (the jQuery UI one) to popup with another view which a separate child view model to be bound to.

The HTML for the dialog content is retrieved using AJAX so I want to be able to call ko.applyBindings once the request has completed, and I want to bind the child view model to just the portion of the HTML loaded via ajax inside the dialog div.

Is this actually possible or do I need to load ALL my views and view models when the page initially loads and then call ko.applyBindings once?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Charlie
  • 10,227
  • 10
  • 51
  • 92

4 Answers4

432

ko.applyBindings accepts a second parameter that is a DOM element to use as the root.

This would let you do something like:

<div id="one">
  <input data-bind="value: name" />
</div>

<div id="two">
  <input data-bind="value: name" />
</div>

<script type="text/javascript">
  var viewModelA = {
     name: ko.observable("Bob")
  };

  var viewModelB = {
     name: ko.observable("Ted")
  };

  ko.applyBindings(viewModelA, document.getElementById("one"));
  ko.applyBindings(viewModelB, document.getElementById("two"));
</script>

So, you can use this technique to bind a viewModel to the dynamic content that you load into your dialog. Overall, you just want to be careful not to call applyBindings multiple times on the same elements, as you will get multiple event handlers attached.

Jeroen
  • 60,696
  • 40
  • 206
  • 339
RP Niemeyer
  • 114,592
  • 18
  • 291
  • 211
  • 18
    If you also want to remove bindings at some point down the road you can call either `ko.cleanNode(document.getElementById("one")` to clean things up or `ko.removeNode(document.getElementById("one")` to clean things up and remove the node from the DOM. – Mike B Oct 15 '12 at 17:32
  • 7
    Just a note that `cleanNode` and `removeNode` will not remove event handlers, so use some caution. In some cases, it is preferable to use the `template` or `with` binding on those areas, so you have new elements rendered. – RP Niemeyer Oct 15 '12 at 17:58
  • 1
    How would you go about cleaning things up completely? There ought to be a way to detach/unbind event handlers created by KO... – Mike B Oct 15 '12 at 18:23
  • 7
    It is currently something that is lacking in KO. We do not specifically intend for people to "rebind" sections. However, KO does attach events using jQuery, if it is referenced, so you can do `$(element).unbind();` to remove all handlers. – RP Niemeyer Oct 15 '12 at 19:22
  • 1
    Is it necessary to do this? `$(element).find("*").each(function () { $(this).unbind(); });` – Mike B Oct 15 '12 at 20:03
  • 5
    Where are these functions (applyBindings, cleanNode, removeNode) documented? I can't find their function signatures on knockoutjs.com. – EricP May 10 '13 at 23:24
  • 2
    Would be nice if this was somewhere easily locatable within the documentation. I didn't even see a mention of it. – Travis Kaufman Jul 12 '13 at 02:44
  • applyBindings 2nd parameter is mentioned in documentation at http://knockoutjs.com/documentation/observables.html – Shital Shah Dec 28 '13 at 06:30
  • Anyone interested in this question may find this related question and answer interesting: http://stackoverflow.com/questions/21186505/including-script-specific-to-an-asp-net-mvc4-view-or-partial-view/21290579#21290579 – BlueMonkMN Jan 23 '14 at 14:32
61

While Niemeyer's answer is a more correct answer to the question, you could also do the following:

<div>
  <input data-bind="value: VMA.name" />
</div>

<div>
  <input data-bind="value: VMB.name" />
</div>

<script type="text/javascript">
  var viewModels = {
     VMA: {name: ko.observable("Bob")},
     VMB: {name: ko.observable("Ted")}
  };

  ko.applyBindings(viewModels);
</script>

This means you don't have to specify the DOM element, and you can even bind multiple models to the same element, like this:

<div>
  <input data-bind="value: VMA.name() + ' and ' + VMB.name()" />
</div>
Jeroen
  • 60,696
  • 40
  • 206
  • 339
mhu
  • 17,720
  • 10
  • 62
  • 93
  • 4
    you can also use "with" to allocate regions of the page to individual models - data-bind="with:VMA" – lexicalscope Aug 10 '12 at 14:23
  • 3
    @flamingpenguin: Yes, but `with` doesn't come cheap, see: [link](http://www.knockmeout.net/2012/03/knockoutjs-performance-gotcha-1ifwith.html) – mhu Aug 14 '12 at 12:30
7

I've managed to bind a custom model to an element at runtime. The code is here: http://jsfiddle.net/ZiglioNZ/tzD4T/457/

The interesting bit is that I apply the data-bind attribute to an element I didn't define:

    var handle = slider.slider().find(".ui-slider-handle").first();
    $(handle).attr("data-bind", "tooltip: viewModel.value");
    ko.applyBindings(viewModel.value, $(handle)[0]);
ZiglioUK
  • 2,573
  • 4
  • 27
  • 32
  • having trouble with ko 2.3, the code above is in a customer handler that is called when I apply the global ko.applyBindings(). So now I get the error "You cannot apply bindings multiple times to the same element.". I'm still trying to figure out why I get the error. Can't we apply a binding to the same variable multiple times, each to different elements? – ZiglioUK Sep 18 '13 at 05:40
  • Here's the version with ko 2.3 that doesn't work: http://jsfiddle.net/ZiglioNZ/tzD4T/458/ – ZiglioUK Sep 18 '13 at 22:26
  • Adding a call to ko.cleanNode() before calling applyBinding to the partial view doesn't seem to help: http://jsfiddle.net/ZiglioNZ/tzD4T/459/ – ZiglioUK Sep 18 '13 at 22:30
  • Solved: I didn't even need to call applyBindings! – ZiglioUK Sep 18 '13 at 23:21
  • ive just edited the knockoutjs source code and commented the part where the function twrows "You cannot apply bindings multiple times to the same element.", now all works ok... i know this is a dirty solution but im new to the library so i dont know how to not to apply it multiple times for my problem. – Geomorillo Nov 25 '13 at 05:18
  • @Geomorillo, not sure about your case, but in my one, I only needed to apply the attribute "data-bind", no need to call ok.applyBindings() again, even if only on a partial view – ZiglioUK Nov 26 '13 at 10:26
0

You should look at the with binding, as well as controlsDescendantBindings http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
Sam Jacobs
  • 346
  • 1
  • 8