Search code examples
knockout.jsko.observablearraycomputed-observable

Can I bind to a computed observable array (knockout)?


I have an observable array of some items (simple pairs of numbers) and I want to bind this to one table. I then want to bind a computed observable which loops the first array and sums up some values by grouping. My foreach loop works fine and sums up the numbers by group (as you can see by uncommenting my alerts), but it never binds to the html. See my fiddle below. Where am I going wrong?

function DataPoint(group, num) {
this.group = group;
this.num = num;
}
function TestViewModel() {
var self = this;

self.data = ko.observableArray([
    new DataPoint(1, 1),
    new DataPoint(2, 5),
    new DataPoint(3, 9),
    new DataPoint(3, 10),
    new DataPoint(4, 3),
    new DataPoint(4, 6),
    new DataPoint(5, 3),
    new DataPoint(5, 9),
    new DataPoint(6, 7),
    new DataPoint(7, 2),
    new DataPoint(8, 8),
    new DataPoint(8, 4),
    new DataPoint(9, 3),
    new DataPoint(11, 6)
])

self.groupedData = ko.computed(function () {
    var total = 0;
    var group = -1;
    var myArray = self.data();
    var counter = 0;
    var rows = self.data().length;
    var result = ko.observableArray([]);
    ko.utils.arrayForEach(myArray, function (item) {
        if (group == -1) {
            group = item.group;
        }
        if (group == item.group) {
            total += parseInt(item.num)
        } else {
            var d = new DataPoint(group, total);
            result.pop(d);
            total = 0;
            group = item.group;
            total += parseInt(item.num)
            //alert(d.group + ':' + d.num);
        }
        if (counter == rows - 1) {
            var d = new DataPoint(group, total);
            result.pop(d);
            //alert(d.group + ':' + d.num);
        }
        counter += 1;
    });
    return result();
    },self);
}

ko.applyBindings(new TestViewModel());

And the html

<body>
Ungrouped Data

<table>
    <thead>
        <tr>
            <td>Group</td>
            <td>Sum</td>
        </tr>
    </thead>
    <tbody data-bind="foreach: data">
        <tr>
            <td>
                <span data-bind="text: group"></span>
            </td>
            <td>
                <span data-bind="text: num"></span>
            </td>
        </tr>
    </tbody>
</table>
<br />
Grouped Data
<table>
    <thead>
        <tr>
            <td>Group</td>
            <td>Sum</td>
        </tr>
    </thead>
    <tbody data-bind="foreach: groupedData">
        <tr>
            <td>
                <span data-bind="text: group"></span>
            </td>
            <td>
                <span data-bind="text: num"></span>
            </td>
        </tr>
    </tbody>
</table>
<script src="Scripts/lib/knockout-3.0.0.js"></script>
<script src="Scripts/app/TestViewModel.js"></script>
</body>

http://jsfiddle.net/gaku6mku/1/

Thanks in advance for any advice!


Solution

  • result.pop(d) should be result.push(d).

    In the immortal words of Homer Simpson.... doh!