如果在返回模板之前删除了元素,则Knockout组件将失败

我有一个KO自定义绑定,它向页面添加一个组件(作为虚拟元素,但我认为这不重要),然后将视图模型应用于它。 组件通过服务器的require加载它的模板。

但是在加载过程中我遇到了一个问题,即更新自定义绑定并从页面中删除元素(如果不需要,我想让它整洁一下)。

这会导致竞争条件 – 如果在KO尝试应用组件时删除元素之前模板的异步查找尚未完成,则无法找到结束标记并引发错误。

我想知道是否有任何人可以建议缓解这个问题? 我已经知道applyBindings上没有回调机制,我不认为 afterRenderCallback会在它到达之前发生错误。 我想知道是否有办法取消,停止或中止该过程 ,但没有。

有任何想法吗?

这是一个演示我的问题的小提琴 。

我的自定义绑定看起来像这样:

 ko.bindingHandlers.customBinding = { update: function(element, valueAccessor){ var $element = $(element) if(ko.unwrap(valueAccessor())){ $element.data("controller", new CustomBindingController(element)); } else { var controller = $element.data("controller"); if(controller){ controller.destroy(); $element.removeData("controller"); } } } } 

它正在调用控制器类,如下所示:

 function CustomBindingController(element){ var self = this, $element = $(element), $component; function init(){ $component = $(""); $("#component-container").append($component); ko.applyBindings( { message: "Binding Applied!" }, $component[0]); self.destroy = destroy; } function destroy(){ $component.remove(); } init.call(self); } 

该组件通过require加载:

  ko.components.register("my-component", { //template: "

" template: { require: "text!component-template" } });

简化的初始化看起来像这样:

  var vm = { shouldBeBound: ko.observable(true) }; ko.applyBindings(vm); vm.shouldBeBound(false); 

实际上,我有一些更复杂的依赖关系,它们在初始化开始后将标志设置为false。

我想我找到了一个解决方案 – 感谢这篇文章 ……

我的组件等的一些修改允许我使用相同的解决方法我有一个更新的小提琴和一些修改样本:

我的组件模板变为:

 

模板绑定将在渲染自身后调用onRendered函数。

传递到虚拟元素的applyBindingsvm必须更改为传递该函数:

 ko.applyBindings( { message: "Binding Applied!", onRendered: onComponentRendered }, $component[0]); 

onComponentRendered看起来像这样:

 function onComponentRendered(){ canDestroy(true); } 

我还需要更改我需要的init函数来包含一些新的observable,一个计算并更改导出的destroy函数:

 shouldDestroy = ko.observable(false); canDestroy = ko.observable(false); destroyComputed = ko.computed(destroy); self.destroy = function(){ shouldDestroy(true); }; 

然后销毁函数检查它是否可以并且应该在此之前销毁(注意它也会自动整理它现在正在调用代码我发现只有虚拟元素没有被删除所以需要jQuery的nextUntil .. 。):

 function destroy(){ if(shouldDestroy() && canDestroy()){ var $template = $($component.get(0)).nextUntil($component.get(1)); $component.remove(); $template.remove(); destroyComputed.dispose() } } 

尼斯。