Pausable observable with KnockoutJS

Posted on in knockout, javascript

Sometimes when working with Knockout you may be in a situation when you want to update a set of observables without delivering notifications to they subscribers (explicitly or by computed observables) as soon each observable is changed. This happens especially when you're using the mapping plugin or something similar.

However, it's not easy to achieve this with builtin knockout functions nor it's very intuitive to do it right.

So I created a function and an extender that make it. Full code is here and I put this jsfiddle to see the use case.

Note that when "Just map" is clicked it logs a weird thing. When "Map with pause" is clicked the notification happens after all observables are changed.

ko.utils.pausableObservable = function(state) {
    var observable = ko.observable(state);
    var pending = [];

    observable.pushNotification = function(object, conf, args) {
        if (!conf.pushed)
        {
            conf.pushed = true;
            pending.push({ object: object, conf: conf, args: args });
        }
    };

    observable.subscribe(function(newValue) {
        if (!newValue)
        {
            var pendingCache = pending;
            pending = [];

            ko.utils.arrayForEach(pendingCache, function(item) {
                item.conf.pushed = false;
            });

            ko.utils.arrayForEach(pendingCache, function(item) {
                item.object.notifySubscribers.apply(item.object, item.args);
            });
        }
    });

    return observable;
};

ko.extenders.pausable = function(target, pausable) {
    var oldNotifySubscribers = target.notifySubscribers;
    var conf = { pushed: false };

    target.notifySubscribers = function(value, event) {
        if (pausable.peek())
        {
            if (!event)
                pausable.pushNotification(target, conf, arguments);
        }
        else
            oldNotifySubscribers.apply(target, arguments);
    };

    return target;
};