gvas / knockout-jqueryui

Knockout bindings for the jQuery UI widgets.
http://gvas.github.com/knockout-jqueryui/
MIT License
103 stars 38 forks source link

Uncaught Error: You cannot apply bindings multiple times to the same element #12

Closed Biohazord closed 10 years ago

Biohazord commented 10 years ago

When upgrade to KO 2.3 this error message "Uncaught Error: You cannot apply bindings multiple times to the same element" appears in the console when binding a jQuery UI Dialog. It appears as though the 2.3 update added the check for this scenario. While the bindings still work it would be nice to not have this appear in the console.

Heres a JSFiddle example with 2.3.0 http://jsfiddle.net/NuBpb/1/ Heres the same code with 2.2.1 http://jsfiddle.net/TYPhu/1/

I'm not familiar enough (yet) with the KO binding life cycle to fully understand the issue and a good fix. I was able to fix the code on my end by adding ko.cleanNode(element); below the ko.applyBindingsToDescendants(bindingContext, element); within the bindingFactory.create function.

I'm still new to Github so sorry if I'm not doing this properly. If I should have created a pull request please let me know and I'll do that.

gvas commented 10 years ago

Thanks for reporting this.

As a workaround for some older browser's z-index bug, jQuery UI moves the dialog's element to the bottom of the page (just before the closing body tag). Knockout parses the elements with a depth first algorithm, so it will try to apply the bindings 2 times to the dialog's element.

You can prevent this error by wrapping your whole page in a div, then invoke ko.applyBinding() on this element (instead of the whole document): http://jsfiddle.net/NuBpb/3/

Regards Gábor

Biohazord commented 10 years ago

Thanks. While the solution is not ideal it does work. I wrapped each thing I was binding with a div and bound it to that specific element.

gvas commented 10 years ago

You don't need to wrap each bound DOM element, you should only create a single top level container div:

<body>
  <div id="container">
  ...
  </div>
</body>

Then invoking

ko.applyBinding(viewModel, document.getElementById('container'));

will do the trick.