Giovanni Azua Giovanni Azua - 6 months ago 128
jQuery Question

Knockoutjs error: You cannot apply bindings multiple times to the same element

I'm trying to automatically populate an element in an existing web page that I can't change and that page uses Knockoutjs. The input element looks like this more or less:

<input maxlength="8" id="xxx" data-bind="textInput: otcInput" type="tel">


Then I use Knockoutjs to attempt to unbind the textInput and populate the input element dynamically with whatever value I need, so I do:

ko.cleanNode($('#xxx'));
ko.applyBindings({
otcInput: ko.observable("123") // populate myself
});


However, this leads to the error
You cannot apply bindings multiple times to the same element
... the question is why? I'm already cleaning the node ... or am I not? is there a way using knockoutjs to see whether there are dangling bindings or leftovers that get in the way while trying to execute my "overriding"
ko.applyBindings
?

I have also tried other ways to set the input value via JQuery sendkeys plugin without success i.e.

$('#xxx').sendkeys('123'); // nothing happens


I also tried:

$('#xxx').unbind();
$('#xxx').off();
$('#xxx').sendkeys('123'); // but again nothing happens

Answer

You're passing a jQuery object to cleanNode. Just like with applyBindings, it has to be a DOM element, not a jQuery object. So:

ko.cleanNode($('#xxx')[0]);
// -------------------^^^

Example — this fails:

ko.applyBindings({
  foo: ko.observable("one")
}, $("#test")[0]);
ko.cleanNode($("#test"));
ko.applyBindings({
  foo: ko.observable("two")
}, $("#test")[0]);
<div id="test">
  <div data-bind="text: foo"></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

...but this (with the [0]) works:

ko.applyBindings({
  foo: ko.observable("one")
}, $("#test")[0]);
ko.cleanNode($("#test")[0]);
ko.applyBindings({
  foo: ko.observable("two")
}, $("#test")[0]);
<div id="test">
  <div data-bind="text: foo"></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

I have also tried other ways to set the input value

If that's your goal, you don't have to muck with the bindings (which probably would have undesirable effects), just:

$("#xxx").val("new value").trigger("change");

The trigger("change") is necessary to get KO to see the change and update the observable. (Or as it's a textInput binding, you might use input rather than change.)

Example — this fails:

// The previously-bound stuff:
var vm = {
  foo: ko.observable("foo")
};
ko.applyBindings(vm, document.body);

// Prove the observable and input are in sync:
console.log("check1", vm.foo(), $("#test").val());

// Update the field
$("#test").val("updated").trigger("change");

// Prove the observable and input are still in sync:
console.log("check2", vm.foo(), $("#test").val());
<input id="test" type="text" data-bind="textInput: foo">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

Comments