我目前正在尝试使用扩展程序在Knockout JS应用程序中实现自动保存功能。当用户停止在字段中输入时,我想调用自动保存功能,而不仅仅是当他们选中它时。
这是我想在observable更新时调用的logChange方法。
//KO Extender for logging changes and calling the autosave function
ko.extenders.logChange = function (target, precision) {
//create a writable computed observable to intercept writes to our observable
var result = ko.pureComputed({
read: target, //always return the original observables value
write: function (newValue) {
debugger;
var current = target(),
valueToWrite = newValue,
attName = precision;
//only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
//self.autoSave(attName, target());
} else {
//if the rounded value is the same, but a different value was written, force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
}).extend({ notify: 'always' });
//initialize with current value to make sure it is rounded appropriately
result(target());
//return the new computed observable
return result;
};
这就是我在viewmodel中设置observable的方法。
self.controlCenter = ko.observable().extend({ rateLimit: { timeout: 500, method: "notifyWhenChangesStop" }, logChange: "ControlCenter" });
这是我可观察的
的html标记 <div class="pure-u-1-2 pure-u-md-1-4 pure-u-lg-1-8">
<label for="ddlControlCenter">Jurisdiction</label>
<input type="text" class="pure-input-1 full-text" list="controlCenterList" data-bind="textInput: controlCenter" />
<datalist id="controlCenterList" data-bind="foreach: controlCenters">
<option data-bind="value: $data"></option>
</datalist>
</div>
调用logChange方法,但它看起来不像应用rateLimit,因为在keypress上立即调用logChange。
答案 0 :(得分:1)
更新
我已经更新了下面的小提琴。您犯的错误是您在更新新值后立即在logChange函数内调用函数。但是rateLimit的概念是,在延迟到所有订阅者之后发送了可观察值被更改的通知。
换句话说,只有observable的订阅者受rateLimit的影响,而不是logChange函数中的任何内容。因此,正确的方法是在订阅者中调用autoSave函数。
function ViewModel() {
var self = this;
self.autoSave = function(attName, value){
console.log(attName + " is now = " + value);
}
self.precision = ko.observable();
ko.extenders.logChange = function (target, precision) {
//create a writable computed observable to intercept writes to our observable
var result = ko.pureComputed({
read: target, //always return the original observables value
write: function (newValue) {
var current = target(),
valueToWrite = newValue;//,
self.precision(precision);
//attName = precision;
//only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
//self.autoSave(attName, target());
} else {
//if the rounded value is the same, but a different value was written, force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
}).extend({ notify: 'always' });
//initialize with current value to make sure it is rounded appropriately
result(target());
//return the new computed observable
return result;
};
self.controlCenter = ko.observable().extend({ rateLimit: { timeout: 500, method: "notifyWhenChangesStop" }, logChange: "ControlCenter" });
self.controlCenters = ko.observableArray([]);
this.controlCenter.subscribe(function (val) {
if (val !== '')
this.controlCenters.push(val);
self.autoSave(self.precision(), val);
}, this);
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="pure-u-1-2 pure-u-md-1-4 pure-u-lg-1-8">
<label for="ddlControlCenter">Jurisdiction</label>
<input type="text" class="pure-input-1 full-text" list="controlCenterList" data-bind="textInput: controlCenter" />
<datalist id="controlCenterList" data-bind="foreach: controlCenters">
<option data-bind="value: $data"></option>
</datalist>
</div>