Is there a way to ignore subscribers on a value change of the observable. Id like to change a value of an observable, but not execute it for the subscribers with knockout.j
An even simpler approach:
ko.observable.fn.silentUpdate = function(value) {
this.notifySubscribers = function() {};
this(value);
this.notifySubscribers = function() {
ko.subscribable.fn.notifySubscribers.apply(this, arguments);
};
};
Use it as follows:
this.status = ko.observable("Happily Married");
this.walkIntoBar();
this.status.silentUpdate("Single");
this.walkOutOfBar(); // careful with exceptions
this.status.silentUpdate("Happily Married");
To be used with caution. We are dealing with an observable object so bad things can happen if you fail to notify your subscribers.
I like the solution provided by @RP Niemeyer when all subscribers need to be ignored. However, for my case, I have an observable with 2-way bindings on a Select control. When using @RP Niemeyer, the Select control isn't updated. So, I really needed a way to turn off specific observers, not all. Here is a generalized solution for this case.
Add extensions methods for 'quiet' subscribe and 'quiet' writes.
ko.observable.fn.ignorePokeSubscribe = function (callback, thisValue, event){
var self = this;
this.subscribe(function(newValue) {
if (!self.paused)
callback(newValue);
}, thisValue, event);
return this;
};
ko.observable.fn.poke = function (newValue) {
this.paused = true;
var result = this(newValue);
this.paused = undefined;
return result;
};
You would subscribe to observable like:
this.name = ko.observable("Bob");
this.name.ignorePokeSubscribe(function(newValue) { /* handler */ }));
Then you would update it without specific notifications by doing:
this.name.poke("Ted"); // standard subscribers still get notified
I came to this question because I was building a paged datagrid. Only 10 rows were shown and each row has a checkbox. The table header had a (de)select all checkbox.
During load tests we discovered that clicking the select all checkbox resulted in updating 1000 observables at once. This took way too long.
It seemed that KO updated the html 1000 times even though only 10 observables were bound to HTML.
If anyone finds this question for the same reason, I would suggest looking into deferred updates. Deferred updates queue notifying subscribers, it notifies your subscribers after your 'thread' is done. Deferred updates is configurable per observable or for your whole application.
http://knockoutjs.com/documentation/deferred-updates.html
Normally this is not possible or advisable, as it potentially allows things to get out of sync in the dependency chains. Using the throttle extender is generally a good way to limit the amount of notifications that dependencies are receiving.
However, if you really want to do this, then one option would be to overwrite the notifySubscribers
function on an observable and have it check a flag.
Here is an extensions that adds this functionality to an observable:
ko.observable.fn.withPausing = function() {
this.notifySubscribers = function() {
if (!this.pauseNotifications) {
ko.subscribable.fn.notifySubscribers.apply(this, arguments);
}
};
this.sneakyUpdate = function(newValue) {
this.pauseNotifications = true;
this(newValue);
this.pauseNotifications = false;
};
return this;
};
You would add this to an observable like:
this.name = ko.observable("Bob").withPausing();
Then you would update it without notifications by doing:
this.name.sneakyUpdate("Ted");