淘汰赛自定义html绑定

时间:2013-12-28 18:09:22

标签: knockout.js custom-binding

我正在尝试使用knockout来创建一个html编辑器/预览器。我使用单个observable设置了一个简单的测试,如下所示:

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">

当页面首次加载时,这似乎工作正常,在其中显示带有'testext'的div,但是只要我将输入字段编辑为类似 <div data-bind=\"text: 'testext2'\"></div>绑定不起作用!

这是淘汰赛的限制,还是我做错了什么?有没有办法预先形成重新绑定?

这里有一个JSFiddle:http://jsfiddle.net/Q9LAA/

2 个答案:

答案 0 :(得分:4)

有一个html绑定可以自动为你插入html(我更喜欢使用setHtml),但它不会评估插入的html上的绑定,你必须重新应用生成的html上的绑定(这是你需要自定义绑定的地方)。

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);
    }
};

这是一个更新的fiddle,展示了它的用途。

答案 1 :(得分:1)

如果我理解正确,你想使用类似Knockout html绑定的东西,但你尝试绑定的HTML包含绑定。问题是您的HTML已加载,但Knockout不会自动对更改的HTML执行applyBindings()

所以你想要的是:

ko.bindingHandlers.bindHTML = {
    init: function () {
        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
        return { 'controlsDescendantBindings': true };
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // setHtml will unwrap the value if needed
        ko.utils.setHtml(element, valueAccessor());

        var elementsToAdd = element.children;

        for (var i = 0; i < elementsToAdd.length; i++) {
            ko.cleanNode(elementsToAdd[i]); //Clean node from Knockout bindings
            ko.applyBindings(bindingContext, elementsToAdd[i]);
        }
    }
};

我使用for循环迭代你要追加的html元素的原因是因为假设你想使用bindHTML绑定追加:

<input type="text" data-bind="value: 'watermelon'" />
<input type="text" data-bind="value: 'orange'" />

使用for循环,每个input元素都会被正确绑定。

这是您更新并正常工作的JSFiddle

注意:请勿执行我在下面显示的内容。

您可能会对具有ko.applyBindings()绑定的元素执行bindHTML,以自动绑定其所有子节点。 这是一个非常糟糕的主意!

如果你这样做,你将进入一个无限循环,因为你会要求knockout再次执行bindHTML,并再次执行。这是一个无限的递归循环!