rows binding

by jcreamer898

HTML

<div data-bind="rows: { columns: 3, items: things }">
    <ul data-bind="foreach: $data">
        <li data-bind="text: name"></li>
    </ul>
</div>

CSS

li { display: inline-block; }

JavaScript

ko.bindingHandlers.rows = {
    init: function (element, valueAccessor, allBindings, data, context) {
        var rows = ko.computed({
            read: function() {
                var index = 0, length, row,
                    options = ko.unwrap(valueAccessor()),
                    data = ko.unwrap(options.items),
                    columnCount = ko.unwrap(options.columns)
                    result = [];

                // we have a sorted array
                // we want to produce rows where each column is sorted alpha
                
                var countInAColumn = Math.ceil(data.length / columnCount);
                var columns = [];
                
                var originalLength = data.length;
                
                while (index < originalLength) {
                    columns.push(data.splice(0, countInAColumn));
                    index += countInAColumn 
                }

                var rows = [];
                
                var cell;
                for (var i = 0, length = columns[0].length; i < length; i++) {
                    var row = [];
                    rows.push(row);
                    for (var j = 0, colLength = columns.length; j < colLength; j++) {
                        cell = columns[j][i];
                        if (cell) {
                            row.push(cell);
                        }
                    }
                }
                
                return rows;
            },
            disposeWhenNodeIsRemoved: element
        });
        
        //apply the real foreach binding with our rows computed
        ko.applyBindingsToNode(element, { foreach: rows }, context);
        
        //tell KO that we will handle binding the children
        return { controlsDescendantBindings: true };
    }
};

var ViewModel = function () {
    this.things = ko.observableArray();
    
    for (var i = 0; i < 99; i++) {
        this.things.push({ name: "item " + i });   
   ...