Can you call ko.applyBindings to bind a partial view?
Asked Answered
O

4

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?

Omen answered 8/9, 2011 at 3:25 Comment(0)
T
431

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.

Tetzel answered 8/9, 2011 at 3:38 Comment(9)
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.Favela
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.Tetzel
How would you go about cleaning things up completely? There ought to be a way to detach/unbind event handlers created by KO...Favela
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.Tetzel
Is it necessary to do this? $(element).find("*").each(function () { $(this).unbind(); });Favela
Where are these functions (applyBindings, cleanNode, removeNode) documented? I can't find their function signatures on knockoutjs.com.Nibelungenlied
Would be nice if this was somewhere easily locatable within the documentation. I didn't even see a mention of it.Redemption
applyBindings 2nd parameter is mentioned in documentation at knockoutjs.com/documentation/observables.htmlEpanorthosis
Anyone interested in this question may find this related question and answer interesting: #21187005Prepositive
S
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>
Slither answered 29/2, 2012 at 15:11 Comment(2)
you can also use "with" to allocate regions of the page to individual models - data-bind="with:VMA"Cephalization
@flamingpenguin: Yes, but with doesn't come cheap, see: linkSlither
V
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]);
Virg answered 21/2, 2012 at 1:34 Comment(6)
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?Virg
Here's the version with ko 2.3 that doesn't work: jsfiddle.net/ZiglioNZ/tzD4T/458Virg
Adding a call to ko.cleanNode() before calling applyBinding to the partial view doesn't seem to help: jsfiddle.net/ZiglioNZ/tzD4T/459Virg
Solved: I didn't even need to call applyBindings!Virg
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.Anisometropia
@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 viewVirg
P
0

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

Pasteurism answered 29/10, 2013 at 17:51 Comment(1)
it looks complicated. Is ko 3.0 going to be any simpler?Virg

© 2022 - 2024 — McMap. All rights reserved.