Reevaluating computed observables

by rniemeyer

HTML

<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<ul data-bind="foreach: highPriorityItems">
    <li>
        <span data-bind="text: name"></span>
    </li>
</ul>
<button data-bind="click: addNewDataBad">Add New Bad</button>
<button data-bind="click: addNewDataGood">Add New Good</button>
<button data-bind="click: addNewData">Add New Simplified</button>
<hr />
Reevaluation Count: <span data-bind="text: highPriorityItems.reevaluationCount"></span>

CSS

ul { margin-left: 10px; }
a { text-decoration: none; }

JavaScript

//track the number of re-evaluations for a computed observable
ko.dependentObservable.fn.trackReevaluations = function() {
    this.reevaluationCount = ko.observable(0);
    this.subscribe(function() {
        this.reevaluationCount(this.reevaluationCount() + 1);
    }, this);        
    return this;
};

var newData = [
    { name: "Task Four", priority: "normal" },
    { name: "Task Five", priority: "high" },
    { name: "Task Six", priority: "high" },
    { name: "Task Seven", priority: "normal" },
    { name: "Task Eight", priority: "high" }
];

var Item = function(name, priority) {
    this.name = ko.observable(name);
    this.priority = ko.observable(priority);    
};

var ViewModel = function() {
    var self = this;

    this.items = ko.observableArray([
        new Item("Task One", "high"),
        new Item("Task Two", "normal"),
        new Item("Task Three", "high")
    ]);    
    
    this.highPriorityItems = ko.computed(function() {
        return ko.utils.arrayFilter(this.items(), function(item) {
            return item.priority() === "high";
        });
    }, this).trackReevaluations();
    
    
    
    this.addNewDataBad = function(data) {
        var item;
        for (var i = 0, j = newData.length; i < j; i++) {
            item = newData[i];
            self.items.push(new Item(item.name, item.priority));   
        }
    };
    
    this.addNewDataGood = function() {
        var item, underlyingArray = self.items();
        for (var i = 0, j = newData.length; i < j; i++) {
            item = newData[i];                       
            underlyingArray.push(new Item(item.name, item.priority));   
        }
        self.items.valueHasMutated();
    };
    
    //simplified
    this.addNewData = function() {
        var newItems = ko.utils.arrayMap(newData, function(item) {
           return new Item(item.name, item.priority); 
        });
        //take advantage of push accepting variable arguments
       ...