On the forums for Knockout, there have been several questions related to temporarily preventing the changes to an observable from being sent out to subscribers. Typically, someone wants to apply many changes to their view model, perhaps as the result of an update call to the server, without having subscriptions triggered until the very end.
This behavior is not currently built into Knockout, but it is still possible to achieve this in a fairly straightforward way. Suppose we have a simple view model that looks like:
1 2 3 4 5 6 7 8 9 |
|
If we receive updates from the server that add/remove users and/or modify the status of each user, then the activeUsers computed observable will be re-evaluated on each and every one of those changes.
To add the ability to pause activeUser
s from being re-evaluated on every change, we can create an augmented computed observable with this added functionality.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
We can now replace our computed observable with a pauseableComputed
:
1 2 3 4 5 |
|
When we want to apply many updates at once, we can wrap our actual updates with the pause()
and resume()
calls.
1 2 3 4 5 6 7 |
|
The key fact that makes this work is that dependency detection is performed each time that a computed observable is re-evaluated. This means that the actual dependencies for a computed observable can change over time. In our case, the dependencies will look like:
When we call pause()
, the _isPaused
flag is set, which forces our computed observable to be re-evaluated. Now, we release our subscriptions to the users
array and to the isActive
flag of each user, but we do keep a cached copy of our latest value to return while we are paused.
When we call resume()
, the cached value is thrown away and our computed observable is re-evaluated, because our only current dependency, the _isPaused
flag, has now changed.
From what I have seen, the most common scenario is that a computed observable depends on many observables that you want to update en masse before re-evaluating the dependentObservable. However, at the bottom of the code for this sample, there is also an implementation that supports pausing writeable computed observables and one for pausing an observableArray as well (would be the same pattern for an observable).
Here is a live sample: