http://jsfiddle.net/keithr/AY3Cp/4/
In the example, I have a columns observableArray and a rows observableArray. The table's header is bound to the columns array. Then the body does a foreach on the rows array. Within that is a nested array that refers back out to the columns, which then calls the row object with the column name to get the value for that column for that row instance.
HTML
<table>
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: name"></th>
</tr>
</thead>
<tbody data-bind="foreach: rows">
<tr data-bind="foreach: $root.columns">
<!-- At this level in the binding the row object is now $parent, and the column is now $data -->
<td data-bind="text: $parent.getColumnValue($data)"></td>
</tr>
</tbody>
</table>
JS
var item = function(val) {
var name = val;
this.getColumnValue = function(col) {
// TODO: Real check for value for col name.
return col.name + "_val_" + name;
};
}
var viewModel = {
rows: ko.observableArray(),
columns: ko.observableArray()
};
for (var i = 0; i < 6; i++) {
viewModel.columns.push({name: 'col' + i });
viewModel.rows.push(new item('test' + i));
}
ko.applyBindings(viewModel);
2nd version: Object to define column header and property on row object to use:
This make the column object more robust with a propertyName and columnHeader properties. It then binds the table row headers to columnHeader, and bind the row cells to the propertyName on the object. Then your row object just has to have properties with all the propertyName values
HTML
<table>
<thead>
<tr data-bind="foreach: columns">
<th data-bind="text: columnHeader"></th>
</tr>
</thead>
<tbody data-bind="foreach: rows">
<tr data-bind="foreach: $root.columns">
<!-- At this level in the binding the row object is now $parent, and the column is now $data -->
<td data-bind="text: $parent[$data.propertyName]"></td>
</tr>
</tbody>
</table>
JS
var column = function(i){
this.propertyName = 'Prop' + i;
this.columnHeader = 'Col ' + i;
}
var item = function(val) {
this.Prop0 = 'p1_' + val;
this.Prop1 = 'p2_' + val;
this.Prop2 = 'p3_' + val;
this.Prop3 = 'p4_' + val;
this.Prop4 = 'p5_' + val;
this.Prop5 = 'p6_' + val;
}
var viewModel = {
rows: ko.observableArray(),
columns: ko.observableArray()
};
for (var i = 0; i < 6; i++) {
viewModel.columns.push(new column(i));
viewModel.rows.push(new item('test' + i));
}
ko.applyBindings(viewModel);