44

Is there a way to check whether applyBindings has been called for a page area or not?

It seems knockout doesn't like when applyBindings is called on the same page more than once.

allicarn
  • 2,859
  • 2
  • 28
  • 47
Chin
  • 12,582
  • 38
  • 102
  • 152

1 Answers1

65

Knockout 2.0 has two functions that you could use for this purpose. ko.dataFor and ko.contextFor take in a node and return either the Knockout data that would be available to it for binding at that scope (dataFor) or the entire binding context at that scope (contextFor), which includes $data, $parent, $parents, and $root.

So, you can do something like:

var isBound = function(id) {
  return !!ko.dataFor(document.getElementById(id));
};

Here is a sample: http://jsfiddle.net/rniemeyer/GaqGY/

However, in a normal scenario you should really look to call ko.applyBindings a single time on your page. It depends on what you are trying to accomplish though. Take a look at this answer for some suggestions on ways to manage multiple view models: Example of knockoutjs pattern for multi-view applications.

Typically, you would do a <div data-bind="with: mySubModel"> and when mySubModel gets populated then that area would appear and be bound.

Community
  • 1
  • 1
RP Niemeyer
  • 114,592
  • 18
  • 291
  • 211
  • Hi, @RPN, the isBound function above is not entirely fail safe. This is because after KO unbinds itself the ko.dataFor(...) continues to return the data it has stored. See this fiddle: http://jsfiddle.net/nabog/6hCfM/6/ – Zephyr was a Friend of Mine Nov 23 '12 at 20:53
  • 1
    @NoelAbrahams - Knockout does not actually "unbind" itself in that case. It recognizes that the element is not a part of the document and disposes of the computed observable that is used to track the dependencies of the element's bindings. This means that the binding will not update further, but not that it is unbound. If you really want to remove KO from an element, then you need to call `ko.cleanNode` which will strip it of its data (it would not remove any event handlers though). Here is a sample: http://jsfiddle.net/rniemeyer/6hCfM/7/ – RP Niemeyer Nov 23 '12 at 22:03
  • Hi, @RPN, I see what you mean. But from the perspective of the isBound function we don't really care about the internals of Knockout. We just want to know that if an observable is changed then does that update the HTML or not. Just wanted to point that out. I hope this behaviour of KO can be fixed. – Zephyr was a Friend of Mine Nov 26 '12 at 11:10
  • 9
    wow bit late that I see this, just got pointed out by a collegue. Why doesn't KO automatically do a check to see if an element is already bound? For usage in single-page applications that would be ideal, as page reloads aren't done, double (or more) bindings are a common issue. Or maybe ko.dataFor() and ko.dataContext() could be used in the documentation on knockoutjs.com? Maybe with demo's even. – rkeet Feb 18 '13 at 09:26
  • There is an unreleased change here to check if bindings have already been applied: https://github.com/SteveSanderson/knockout/pull/466. However, the intention has always been that you use `with` or `template` bindings around your sections that need to be "re-bound" rather than calling applyBindings multiple times. This pattern alleviates any of these issues. – RP Niemeyer Feb 18 '13 at 13:33
  • Do any of you know how you could tell _from the ViewModel itself_ if it has been bound already? – allicarn Jul 19 '13 at 18:25
  • The view model itself would not really know that it had been bound. The best that you could do would be something like this: http://jsfiddle.net/rniemeyer/GMcJE/ by using `getSubscriptionsCount`. Obviously if you access that observable in your view model in a computed, then it will create a dependency as well. – RP Niemeyer Jul 19 '13 at 18:40
  • 3
    Just wanted to add that ko.dataFor() will look up the DOM hierarchy and return parent data even if a part of the page was never really bound. It is entirely possible that some part of the page has been deliberately marked with controlsDescendantBindings: true. So it is available for binding despite the fact that ko.dataFor() will return parent data. – AGS May 14 '14 at 19:08
  • 2
    I guess this is a pretty old thread, but I wanted to add a correction to @RPNiemeyer 's comment, because calling `ko.cleanNode` does strip jQuery event bindings in addition to the Knockout event bindings. (See http://stackoverflow.com/questions/16479637) – Sean the Bean Dec 19 '14 at 18:53