Search code examples
knockout.jscustom-binding

knockout custom html binding


I am trying to use knockout to create a html editor/previewer. I set up a simple test with a single observable as follows:

JS:

var ViewModel = function() {
    this.content = ko.observable("<div data-bind=\"text: 'testext'\"></div>");
};

ko.bindingHandlers.bindHTML = {
    'init': function () {
    },
    'update': function (element, valueAccessor) {                         
        ko.utils.setHtml(element, valueAccessor());
    }
}

ko.applyBindings(new ViewModel());

HTML:

<input type="text" data-bind="value: content">

This seems to work fine when the page first loads, displaying a div with 'testext' in it, however as soon as I edit the input field to something like <div data-bind=\"text: 'testext2'\"></div> the binding doesn't work!

Is this a limitation of knockout, or is there something I'm doing wrong? Is there a way of preforming a rebind?

A JSFiddle is available here: http://jsfiddle.net/Q9LAA/


Solution

  • There is an html binding that can insert html for you automatically (I would prefer this over using setHtml), but it doesn't evaluate the bindings on the inserted html, you have to reapply the bindings on the generated html (and that is where you would need a custom binding).

    ko.bindingHandlers.bindHTML = {
        init: function () {
            // we will handle the bindings of any descendants
            return { controlsDescendantBindings: true };
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            // must read the value so it will update on changes to the value
            var value = ko.utils.unwrapObservable(valueAccessor());
            // create the child html using the value
            ko.applyBindingsToNode(element, { html: value });
            // apply bindings on the created html
            ko.applyBindingsToDescendants(bindingContext, element);
        }
    };
    

    Here's an updated fiddle demonstrating its use.