我有一个自定义绑定处理程序,可以将其绑定到视图模型中的复杂对象。
任何可观察对象的属性更新时,绑定处理程序将正常工作,并且会调用update
函数。但是,{<1>}函数会为每个更新的属性调用,由于我依赖于整个对象的可用性和最新性,因此导致行为异常。
我理解为什么会发生这种情况,因为每个属性都导致调用更新,并且我想我知道如何防止这种情况-通过使用Knockout的deferred updates功能。
但是,我无法找到如何仅为我的自定义绑定中的可观察到的启用延迟更新。我不想在整个应用程序中启用它,因为我正在将绑定编写为库函数。
我尝试了许多不同的方法,包括:
update
函数; init
; valueAccessor
with a new observable with deferred
applied; 所有方法都无效。
我还没有找到任何其他自定义绑定处理程序,这些处理程序离这种功能很近,并且一直在尝试将其与其他功能组合在一起。
我的绑定代码本身是相对简单的,我要获取绑定的对象,然后简单地拆分参数并将它们传递给Code Mirror实例。
valueAccessor
我的HTML代码是:
ko.bindingHandlers.editor = {
init: function(element, valueAccessor, allBindingsAccessor) {
var observableValue = ko.utils.unwrap(valueAccessor());
initEditor(element, observableValue, allBindingsAccessor);
},
update: function(element, valueAccessor, allBindingsAccessor) {
var observableValue = ko.unwrap(valueAccessor());
createEditor(codeEditorDiv, observableValue);
resize();
updateEditor(element, observableValue, allBindingsAccessor);
}
};
我在ViewModel上使用Dotnetify,所以它是一个合理的复杂C#类,但是可以说绑定正在起作用并正在更新,但是我需要它仅在所有属性都具有后才调用“ update”已更新。
答案 0 :(得分:2)
很遗憾,您没有展示initEditor
,createEditor
和updateEditor
对observableValue
的作用,因为这可能是您扩展可观测量的地方。
绑定的init
和update
方法创建计算依赖关系,这意味着从init
开始在调用堆栈中展开的任何可观察对象将导致update
方法被调用。
在一个抽象示例中:
const someVM = ko.observable({
a: ko.observable(1),
b: ko.observable(2),
c: ko.observable(3)
});
// Some function that unwraps properties
const logABC = function(vm) {
console.log(
vm.a(),
vm.b(),
vm.c()
);
}
// Regular binding update:
ko.computed(function update() {
console.log(
"Regular binding update:",
)
logABC(someVM())
});
// Change VM
someVM(someVM());
// Change a, b, and c
someVM().a("A");
someVM().b("B");
someVM().c("C");
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
请注意,update
被称为:
有多种解决方法,其中最简单的方法是在绑定的computed
方法内创建自己的init
,并将其扩展为deferred
。
const someVM = ko.observable({
a: ko.observable(1),
b: ko.observable(2),
c: ko.observable(3)
});
const getABC = function(vm) {
return [vm.a(), vm.b(), vm.c()].join(", ");
}
ko.bindingHandlers.renderABC = {
init: function(el, va) {
el.innerText += "Init.\n";
// This ensures any inner unwrapping gets deferred
var updateSub = ko.computed(function update() {
el.innerText += getABC(ko.unwrap(va())) + "\n";
}).extend({ deferred: true });
ko.utils.domNodeDisposal.addDisposeCallback(el, function() {
updateSub.dispose();
});
}
}
ko.applyBindings({ someVM: someVM });
// Change VM
someVM(someVM());
// Change a, b, and c
someVM().a("A");
someVM().b("B");
someVM().c("C");
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<pre data-bind="renderABC: someVM"></pre>