我已经嵌套了自定义的敲除绑定。
顶级绑定扩展了绑定上下文并添加了它。
子绑定需要是子绑定,因为它使用添加到绑定上下文的数据。
Psuedo-code -
ko.bindingHandlers.map = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
let map = new map({element: element});
let innerBindingContext = bindingContext.extend({"map": map});
ko.applyBindingsToDescendants(innerBindingContext, element);
// tell KO *not* to bind the descendants itself, otherwise they will be bound twice
return { controlsDescendantBindings: true };
}
};
ko.bindingHandlers.overlay = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
let map = bindingContext.map;
let overlay = new overlay({element: element});
map.addOverlay(overlay);
// have tried 1. code below,
// 2. createChildContext,
// 3. not returning anything,
// 4. ko.cleanNode(element); prior to binding,
// all with the same error
let innerBindingContext = bindingContext.extend({});
ko.applyBindingsToDescendants(innerBindingContext, element);
return { controlsDescendantBindings: true };
}
};
var vm = {
someVariable: ko.observable("test");
}
ko.applyBindings(vm);
HTML -
<div data-bind="map:{}">
<div data-bind="overlay:{}">
<span data-bind="text:someVariable"></span>
</div>
</div>
无论我做什么,我都会收到错误 -
“您不能多次将绑定应用于同一元素。”
绑定实际上是利用了一个javascript库。该库将子绑定dom元素移动到HTML中的其他位置。我认为这是问题所在。
为什么由于移动了dom元素而导致此错误,我该如何解决?
答案 0 :(得分:1)
每当通过调用applyBindings初始化knockout时,它会递归遍历目标元素或文档中的每个节点以查找并应用绑定。我认为可能发生的是时间问题,淘汰尝试在每个独特元素同时移动时应用绑定。这类似于在循环时修改数组的长度。
当自定义绑定返回{controlsDescendantBindings: true}
时,它会从主绑定进程中删除所有子节点。 Knockout将阻止其递归更深入,并且只有手动完成绑定才会应用于这些元素。但是,自定义绑定附加到的根元素仍然是该进程的一部分,并且已经绑定(根据定义 - 首先触发自定义绑定)。因此,虽然这有助于它不能解决主要问题,即根元素被绑定,然后移动到DOM中的其他位置,以便敲除&#34;找到&#34;再次尝试再绑定它。
在应用第二遍之前用ko.cleanNode
清除第一次传递绑定是一种诊断性攻击。理想情况下,您应该等待应用绑定,直到元素完成被其他插件移动为止。在允许插件移动元素之前允许敲除完成所有内容的情况下,反向也可能有效,但如果元素被真正删除然后重新添加而不是仅仅被移动,则可能导致其他问题。这取决于插件的工作方式。
修改强>:
如果您不能将插件的时间与绑定分开,另一种可能的解决方案是将映射绑定到包装器元素上。这样,插件所针对的元素所有都可以通过{controlsDescendantBindings: true}
从绑定过程中删除。当插件移动目标节点时,它会将包装器留在后面,每个人都很高兴。 (只要地图绑定不需要对可观察对象的变化作出反应)
ko.bindingHandlers.map = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
let target = $(element).children();
let map = new Map({element: target});
let innerBindingContext = bindingContext.extend({"map": map });
ko.applyBindingsToDescendants(innerBindingContext, target);
// tell KO *not* to bind the descendants itself, otherwise they will be bound twice
return { controlsDescendantBindings: true };
}
};