Say your items look like this:
var Item = function(name, group) {
this.name = name;
this.group = group;
}
And they're in an observable array:
var items = ko.observableArray([
new Item("Item1", "group1"),
new Item(/* ... */),
/* et cetera */
]);
To create an object with all items sorted by group, create a computed:
var itemsByGroup = ko.computed(function() {
return items().reduce(function(result, item) {
if (!result[item.group]) {
result[item.group] = [];
}
result[item.group].push(item);
return result;
}, {});
});
You need to create a computed 2-dimensional array to use the knockout foreach binding.
var itemGroups = ko.computed(function() {
return Object.keys(itemGroups())
.map(function(key) { return itemGroups()[key]});
});
Now, you can create your lists using HTML markup like so:
<ul data-bind="foreach: itemGroups">
<li>
<ul data-bind="foreach: $data">
<li data-bind="text: name"></li>
</ul
</li>
<ul>
If you want to add group labels and such, you can return an object with a label property and the items in an items array. Experiment with it using the fiddle below:
var Item = function(name, group) {
this.name = name;
this.group = group;
}
var items = ko.observableArray([
new Item("1", "A"),
new Item("2", "A"),
new Item("3", "B"),
new Item("4", "C")
]);
var itemsByGroup = ko.computed(function() {
return items().reduce(function(result, item) {
if (!result[item.group]) {
result[item.group] = [];
}
result[item.group].push(item);
return result;
}, {});
});
var groupedArray = ko.computed(function() {
var grouped = itemsByGroup();
return Object.keys(grouped)
.map(function(key) {
return grouped[key]
});
});
ko.applyBindings({
groupedArray: groupedArray
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: groupedArray">
<li>
<ul data-bind="foreach: $data">
<li data-bind="text: name"></li>
</ul
</li>
<ul>