Knockout自定义bindingHandler无法对附加元素应用绑定

时间:2014-07-25 09:07:13

标签: javascript jquery knockout.js

我正在尝试使用自定义bindingHandler来添加类似模板的东西,因此需要自己的模型。 仅供参考(但不需要了解问题):真正的目标是管理位于具有此bindingHandler的DIV内的多个组件。

但是,我无法创建自定义上下文但是让KO无法尝试绑定我创建的元素(并且已经使用自定义bindingHandler对其进行了绑定)。

我得到的只是典型的错误: 未捕获错误:您无法多次将绑定应用于同一元素。

会发生什么?

我的猜测是:

  • Knockout正在执行第一个applyBinding并在其中的元素上搜索绑定处理程序

  • 它执行初始化过程

  • 初始化使用新元素上的applyBindings创建新上下文

  • 完成该操作后,淘汰似乎没有考虑创建的元素(和已经绑定的元素)的“allowBindings:false”并尝试绑定两次事物......

代码(jsfiddle)

http://jsfiddle.net/darknessm0404/tB6Zv/3/

<div id="view">
    viewModel content.
    <p data-bind="text:data"></p>
    <div data-bind="customComponent:{}">
        <p>Need to have is own model. Another element is added while the constructor of the viewModel is instancied.</p>
    </div>
</div>

ko.bindingHandlers.allowBindings = {
    init: function (elem, valueAccessor) {
        // Let bindings proceed as normal *only if* my value is false
        var shouldAllowBindings = ko.unwrap(valueAccessor());
        return { controlsDescendantBindings: !shouldAllowBindings };
    }
};

ko.bindingHandlers.customComponent = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            // Append new element
            var $component = $('<div data-bind="allowBindings:false">customComponent content: <span data="text:data"></span><div>').appendTo($(element));
            // Apply bindings on newly created element
            console.log('2.A. customComponent -> applyBindings -> started');
            ko.applyBindings({
                data: 'COMPONENT MODEL DATA'
            }, $component[0]);
            console.log('2.A. customComponent -> applyBindings -> completed');
        }
};

console.log('1.A. view -> applyBindings -> started');
ko.applyBindings({
    data: 'VIEW MODEL DATA'
}, $('#view')[0]);
console.log('1.B. view -> applyBindings -> completed');

如何通过说淘汰以防止绑定这些已绑定的项目来使其工作?

如何强制knockout解析这些已绑定的项目?我试图将allowBindings:false添加到包含“customComponent:...”的DIV,它仍然初始化但我无法从中获取model.data属性。


解决方案

这是我用过的代码的一部分。我只是忘记添加return { controlsDescendantBindings: true };以防止KO对创建的子元素应用绑定。

它可能无法直接编译,但想法是一样的:在绑定创建的新元素上绑定一个新的childContext,并用当前绑定上下文初始化该项的兄弟。

有了这个,我就能够管理组(div)中的组件,这些组件可以访问父模型(此处未显示的代码,通过$ .closest完成并使用$ .data存储)等等要求自己被附加到模板引用的“panel.list”。

 init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        //...
        // Template creation
        var $template = $('<ul></ul>').prependTo($(element));

        Quadratus.ko.dataBind($template, {
            foreach: 'panel.list'
        });
        $('<li><span data-bind="text:\'hello\'"></span></li>').appendTo($template);

        ko.applyBindings(bindingContext.createChildContext(model), $template[0]);

        $template.siblings().each(function () {
            // Apply current bindingcontext on siblings
            ko.applyBindings(bindingContext, this);
        });
 return { controlsDescendantBindings: true };

1 个答案:

答案 0 :(得分:4)

从customComponent { controlsDescendantBindings: true }函数返回init

请参阅http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html

以下是对小提琴的更新:http://jsfiddle.net/tB6Zv/4/

除了添加controlsDescendantBindings返回值之外,我还进行了以下更改:

  • 已移除allowBindings: false
  • 已修复data="text: data"应为data-bind="text: data"
  • 将新元素的ko.applyBindings更改为ko.applyBindingsToDescendants,这种情况下更常用