This problem piqued my interest, so I decided to explore it further. After some experimentation, I came to the conclusion that a custom extender is needed for this specific scenario. I managed to find one that mimics the functionality of rateLimit, and with a few modifications, it appears to meet your requirements.
By utilizing this solution, you can implement the following:
self.companyValue = ko.observable().extend({ customRateLimit: 5000 });
This approach ensures that the initial change takes effect immediately, while subsequent changes are subject to rate limiting.
Here is the demo
Below is the code snippet that you can run:
ko.extenders.customRateLimit = function(target, timeout) {
var writeTimeoutInstance = null;
var currentValue = target();
var updateValueAgain = false;
var interceptor;
var isFirstTime = true
if (ko.isComputed(target) && !ko.isWriteableObservable(target)) {
interceptor = ko.observable().extend({
customRateLimit: timeout
});
target.subscribe(interceptor);
return interceptor;
}
return ko.dependentObservable({
read: target,
write: function(value) {
var updateValue = function(value) {
if (isFirstTime) {
target(value);
isFirstTime = false;
} else {
if (!writeTimeoutInstance) {
writeTimeoutInstance = setTimeout(function() {
writeTimeoutInstance = null;
if (updateValueAgain) {
updateValueAgain = false;
updateValue(currentValue);
}
target(value);
}, timeout);
}
}
}
currentValue = value;
if (!writeTimeoutInstance)
updateValue(currentValue);
else
updateValueAgain = true;
}
});
}
function AppViewModel() {
this.text = ko.observable().extend({
customRateLimit: 1000
});
this.rateLimited = ko.computed(this.text).extend({
customRateLimit: 1000
});
}
ko.applyBindings(new AppViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-debug.js"></script>
<h4>Change value is default so move the focus out of the input to change values.</h4>
<div>
Enter Text: <input type='text' data-bind='value: text' />
</div>
<div>
Rete Limited <small>(after the first change)</small>: <input type='text' data-bind='value: text' />
</div>
<div>
Rete Limited Computed <small>(after the first change)</small>: <input type='text' data-bind='value: rateLimited' />
</div>
After entering text in the first input, observe how the change propagates instantly to other inputs. However, any subsequent changes following the initial one are delayed as per the rate limit.
This method allows you to extend both observables and computed observables seamlessly.