0
votes

I have created a KnockoutJS application, and I also must use some third-party stuff with it. My third-party stuff uses vanilla Javascript to insert a div into the markup rendered by Knockout. Once this happens, Knockout stops working.

Here's a fiddle that encapsulates the problem: http://jsfiddle.net/p5o8842w/1/

HTML:

<div style="margin-bottom:50px;">
    <button onclick='BindVM();' >Bind</button>
    <button onclick='ThrowWrench();'>Throw a Wrench Into It</button>
</div>

<div id="ViewModel" data-bind="template: 'Template'">
</div>

<script type="text/html" id='Template'>
    <div style="margin-bottom:20px;">
        <span data-bind="text: Name"></span>
    </div>
    <div id="infoDiv">
        <input type="text" data-bind="text: Name, value: Name, valueUpdate: 'keyup'" />
    </div>
</script>

JavaScript:

function BasicVM () {
    var self = this;

    self.Name = ko.observable('The Name');
    self.Title = ko.observable('The Title');
}

function BindVM() {
    var vm = new BasicVM();
    var element = document.getElementById('ViewModel');
    ko.cleanNode(element);
    ko.applyBindings(vm, element);
}

function ThrowWrench() {    
    var element = document.getElementById('infoDiv');
    element.innerHTML = "<div class='container'>" + element.innerHTML + '</div>';
}

First, click 'Bind.' Notice that the textbox is bound to the span; change the box, you change the span.

Then, click 'Throw a Wrench Into It.' Now, the textbox is no longer data-bound to the ViewModel, and typing into it doesn't impact the span.

Things I can't do:

  1. Take the third-party code and refactor/integrate it into my Knockout stuff.
  2. Run the third-party code before I render with Knockout (which I think would help).
  3. Call ko.applyBindings again after running the third-party code. I can do this, but then Knockout destroys what the third-party code did, so I'd have to run it again, which would cause the same problem again.

Is there any way around this?

1

1 Answers

0
votes

Because replacing element.innerHTML it's losing is binding. In order to overcome this. Two method are available: 1- Rebind the new element

2- Else

var element = document.getElementById('infoDiv');
var parent = element.parentNode;
var wrapper = document.createElement('div');
parent.replaceChild(wrapper, element);
wrapper.appendChild(element);

This is updated url: http://jsfiddle.net/p5o8842w/5/