When you extend an observable, the extender typically wraps the observable with another with the desired behavior. You could keep a reference to the original observable which will allow you to make direct writes to it all while exposing your throttled version of the observable normally.
e.g.,
var myObservable = ko.observable('foo');
var myThrottledObservable = myObservable.extend({ throttle: 500 });
myThrottledObservable('bar'); // delayed
myObservable('baz'); // immediate
In your particular use case, rather than throttling the waiting
observable, throttle the outstandingRequests
observable and use the throttled value in waiting
.
var outstandingRequests = ko.observable(0);
// throttled requests for the waiting observable
var throttledOutstandingRequests = outstandingRequests.extend({ throttle: 500 });
// true if any requests are outstanding
var waiting = ko.computed(function() {
return throttledOutstandingRequests() > 0;
};
// These are called when AJAX requests begin or end
function ajaxBegin() {
outstandingRequests(++outstandingRequests());
}
function ajaxEnd() {
outstandingRequests(--outstandingRequests());
}
Writes to your outstandingRequests
observable happen immediately but your waiting
observable will effectively be throttled.
Alternatively, a cleaner solution in my opinion would be to reimplement the throttled
extender to add the ability to update immediately.
ko.extenders['throttleEx'] = function(target, timeout) {
// Throttling means two things:
// (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
// notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
target['throttleEvaluation'] = timeout;
// (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
// so the target cannot change value synchronously or faster than a certain rate
var writeTimeoutInstance = null;
var throttled = ko.dependentObservable({
'read': target,
'write': function(value) {
clearTimeout(writeTimeoutInstance);
writeTimeoutInstance = setTimeout(function() {
target(value);
}, timeout);
}
});
// add function to set the value directly
throttled['immediate'] = function(value) {
target(value);
};
return throttled;
};
Then to use it:
var waiting = ko.computed(function() {
return outstandingRequests() > 0;
}.extend({ throttleEx: 500 });
// These are called when AJAX requests begin or end
function ajaxBegin() {
outstandingRequests.immediate(++outstandingRequests());
}
function ajaxEnd() {
outstandingRequests.immediate(--outstandingRequests());
}