ko with asynch computed + timer

by nickkell

HTML

<script src="https://github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.debug.js"></script>
<input type="number" data-bind="value: currentPage" />
<div data-bind="text: ko.toJSON($root)"></div>

JavaScript

ko.extenders.async = function(target, option) {
    var asyncComputed = function(evaluator, owner) {
        var result = ko.observable(),
            currentDeferred;

        result.loading = ko.observable(false); // Track whether we're waiting for a result
        ko.computed(function() {
            // Abort any in-flight evaluation to ensure we only notify with the latest value
            if (currentDeferred) {
                currentDeferred.reject();
            }

            var evaluatorResult = evaluator.call(owner);
            // Cope with both asynchronous and synchronous values
            if (evaluatorResult && (typeof evaluatorResult.done == "function")) { // Async
                result.loading(true);
                currentDeferred = $.Deferred().done(function(data) {
                    result(data);
                }).always(function() {
                    result.loading(false);
                });
                evaluatorResult.always(currentDeferred.resolve);
            } else { // Sync
                result(evaluatorResult);
            }
        });

        return result;
    };

    var o = asyncComputed(option.deferred, option.owner || target());

    return o;
};
ko.extenders.intervalAsync = function(target, option) {
    var o =  ko.observable();

    setInterval(function() {
        ko.observable().extend({
            async: option.async  
        }).subscribe(function(nv) {
            o(nv);
        });
        
    }, option.interval || 500);

    return o;
};

function VM() {
    var self = this;

    self.currentPage = ko.observable(1);

    self.results = ko.observable().extend({
        async: {
            deferred: function() {
                return $.post('/echo/json/', {
                    json: ko.toJSON(self.currentPage)
                }, 'json').pipe(function(json) {
                    return json;
                });
            }
        }
    });

    self.intervalAsync = ko.observable().extend({
       ...