If you need to do this dynamically in KO, then here is an example of a binding that wraps the normal foreach binding and creates a computed on the fly that returns a structure with rows/columns based on a "count" observable.
ko.bindingHandlers.foreachGroups = {
init: function(element, valueAccessor) {
var groupedItems,
options = valueAccessor();
//create our own computed that transforms the flat array into rows/columns
groupedItems = ko.computed({
read: function() {
var index, length, group,
result = [],
count = +ko.utils.unwrapObservable(options.count) || 1,
items = ko.utils.unwrapObservable(options.data);
//create an array of arrays (rows/columns)
for (index = 0, length = items.length; index < length; index++) {
if (index % count === 0) {
group = [];
result.push(group);
}
group.push(items[index]);
}
return result;
},
disposeWhenNodeIsRemoved: element
});
//use the normal foreach binding with our new computed
ko.applyBindingsToNode(element, { foreach: groupedItems });
//make sure that the children of this element are not bound
return { controlsDescendantBindings: true };
}
};
You would use it like:
<div data-bind="foreachGroups: { data: items, count: count }">
<ul data-bind="foreach: $data">
<li data-bind="text: $data"></li>
</ul>
</div>
Here is a sample: http://jsfiddle.net/rniemeyer/F48XU/
For your specific case though, I would probably:
- remove the
count option and just pass in the items
- create your own
count observable in the init function.
- add a
resize event handler that runs your logic and updates the count observable appropriately.
It might look like (fill in your specific resize logic):
ko.bindingHandlers.foreachGroups = {
init: function(element, valueAccessor) {
var groupedItems,
data = valueAccessor(),
count = ko.observable(1);
ko.utils.registerEventHandler(window, "resize", function() {
//run your calculation logic here and update the "count" observable with a new value
});
//create our own computed that transforms the flat array into rows/columns
groupedItems = ko.computed({
read: function() {
var index, length, group,
result = [],
itemsPerRow = +ko.utils.unwrapObservable(count) || 1,
items = ko.utils.unwrapObservable(data);
//create an array of arrays (rows/columns)
for (index = 0, length = items.length; index < length; index++) {
if (index % itemsPerRow === 0) {
group = [];
result.push(group);
}
group.push(items[index]);
}
return result;
},
disposeWhenNodeIsRemoved: element
});
//use the normal foreach binding with our new computed
ko.applyBindingsToNode(element, { foreach: groupedItems });
//make sure that the children of this element are not bound
return { controlsDescendantBindings: true };
}
};