How to defer observable updating?

Filtering experiments

by gene

HTML

<script src="https://github.com/downloads/SteveSanderson/knockout/knockout-2.0.0.js"></script>
<script src="https://raw.github.com/mbest/knockout-deferred-updates/master/knockout-deferred-updates.js"></script>
<table border="3" cellpadding="2">
    <tr>
        <th>Lists</th>
        <th>Documents</th>
    </tr>
    <tr>
        <td class="list">
            <ul class="lists" data-bind="foreach: views">
                <li data-bind="text: label, click: $parent.selectedView"></li>
            </ul>
            <br />
            <div data-bind="with: selectedView">
                <div data-bind="with: container">
                <ul class="filters" data-bind="foreach: filters">
                    <li data-bind="text: label, click: $parent.selectedFilter, css: {selectedFilter: selected()}"></li>
                </ul>        
                </div>                    
            </div>
        </td>
        <td class="detail"  data-bind="with: selectedView">
            <div data-bind="foreach: pageList">
                <div class="pageButton" data-bind="text: $data, click: $parent.goToPage"></div>
            </div>
            <button data-bind="click: sortById">By id</button>
            <button data-bind="click: sortByTitle">By title</button>            
            <ul class="items" data-bind="foreach: rows">
                <div data-bind="click:discount">
                    <span data-bind="text: id"></span> 
                    <span data-bind="text: title"></span>
                    <span data-bind="text: price"></span>
                </div>
            </ul>
 
        </td>
    </tr>
</table>
    <button data-bind="click: addDocument">Add doc</button>

CSS

.document {
    display: inline;
    margin-right: 10px;
    text-decoration: none;
}

body {
    font-family: sans-serif;
    font-size: 10pt;
}

.lists > li {
    cursor: pointer;
}

.filters > li {
    cursor: pointer;
}

.selectedFilter {
    font-weight: bold;
}

.pageButton {
    border: 1px solid blue;
    margin: 4px;
    display: inline;
    padding: 2px;
    width: 10px;
    height: 10px;
    cursor: pointer;
}

.items {
    padding: 6px;
    border: 1px solid grey;
    margin: 6px;
}

td {
    padding: 6px;
}

JavaScript

function Document(id, title, price) {
    var self = this;
    this.id = ko.observable(id);
    this.title = ko.observable(title);
    this.price = ko.observable(price);
    
    this.discount = function() {
        this.price(this.price()*0.9);
    }
}
        
        
var id = 1;
var docs = [
    new Document(id++, 'first doc', 10),
    new Document(id++, 'second doc', 10),
    new Document(id++, 'third doc', 12),
    new Document(id++, 'fourth doc', 12),
    new Document(id++, 'fifth doc', 14),
    new Document(id++, 'sixth doc', 14),
    new Document(id++, 'seventh doc', 15),
    new Document(id++, 'eighth doc', 15),
    new Document(id++, 'ninth doc', 20),
    new Document(id++, 'tenth doc', 20),
    new Document(id++, 'eleventh doc', 20),
    new Document(id++, 'twlevth doc', 20),
    new Document(id++, 'thirteenth doc', 10),
    new Document(id++, 'fourteenth doc', 9),
    new Document(id++, 'fifteenth doc', 8),
    new Document(id++, 'sixteenth doc', 7),
    new Document(id++, 'seventeenth doc', 6),
    new Document(id++, 'eighteenth doc', 8),
    new Document(id++, 'nineteenth doc', 5),
    new Document(id++, 'twentieth doc', 3)
    ];


function Filter(label, range) {
    var self = this;
    this.label = ko.observable(label);
    this.range = ko.observable(range);
//    this.container = container;
    
    this.matches = function(doc) {
        var rnge = self.range();
        var price = self.price();
        return price >= rnge[0] && price < rnge[1];
    };
    
    this.selected = ko.observable(false);
}

function FilteredView(filterList, allItems) {
    var self = this;
    
    this.filters = ko.observableArray(filterList);
    this.selectedFilter = ko.observable();
    this.selectedFilter.subscribe(function(f) {
        var filters = self.filters();
        for (var i=0; i<filters.length; i++)
            filters[i].selected(false);
        f.selected(true);
    });                
    
    this.allItems = allItems;
    
    this.items =...