Knockout.js Table Sorting
This table shows ascending/descending by Multiple column headers
by CodeRenaissance
HTML
<script src="http://cloud.github.com/downloads/coderenaissance/knockout.mapping/knockout-1.3.0beta.js"></script>
<script src="http://cloud.github.com/downloads/coderenaissance/knockout.mapping/knockout.mapping.js"></script>
<div id="container">
<table>
<thead>
<tr>
<td data-bind="click:$root.actions.sortCol1"> col1 </td>
<td data-bind="click:$root.actions.sortCol2"> col2 </td>
<td data-bind="click:$root.actions.sortCol3"> col3 </td>
</tr>
</thead>
<tbody data-bind="foreach:items">
<tr>
<td><span data-bind="text:$data.c1"/></td>
<td><span data-bind="text:$data.c2"/></td>
<td><span data-bind="text:$data.c3"/></td>
</tr>
</tbody>
</table>
</div>
CSS
td{
padding: 2px 10px;
}
thead td{
cursor: pointer;
background:#ccc;
}
thead td:hover{
cursor: pointer;
background:#eee;
}
thead .ascending, thead .ascending:hover{
background:red;
color:black;
}
thead .descending, thead .descending:hover{
background:blue;
color: white
}
JavaScript
var SortManager = function(observableArrayOfObjects) {
var ascendingTracker = {};
var lastColumnSorted = "";
var fnSort = function(columnName, isNumeric, target) {
var isAscending, selected, unselected, repeatedColumnSort;
repeatedColumnSort = (columnName == lastColumnSorted);
lastColumnSorted = columnName;
isAscending = ascendingTracker[columnName] = (repeatedColumnSort && ascendingTracker[columnName] ? false : true);
selected = $(target);
unselected = selected.siblings();
selected.toggleClass('ascending', isAscending).toggleClass('descending', !isAscending);
unselected.removeClass('ascending').removeClass('descending');
observableArrayOfObjects.sort(
function doNumericSort(left, right) {
left = isNumeric ? (parseFloat(ko.utils.unwrapObservable(left[columnName])) || 0) : ko.utils.unwrapObservable(left[columnName]);
right = isNumeric ? (parseFloat(ko.utils.unwrapObservable(right[columnName])) || 0) : ko.utils.unwrapObservable(right[columnName]);
return (left === right ? 0 : (left < right ? -1 : 1)) * (isAscending ? 1 : -1);
});
};
return {
numericSort: function doNumericSort(columnName, target) {
fnSort(columnName, true, target);
},
textSort: function doTextSort(columnName, target) {
fnSort(columnName, false, target);
}
};
};
var model= {//this code is injected into the page on the server or retrieved via ajax
items: [
{ c1: "d", c2: "210", c3: "1005"},
{ c1: "z", c2: "1", c3: "205"},
{ c1: "a", c2: "20", c3: "2005"}
]
};
var viewModel = ko.mapping.fromJS(model);//create a knockout viewModel
//add actions to your model
viewModel.actions = {
getSortManager: function() {
return this.itemSortManager = this.itemSortManager || new SortManager(viewModel.items);
},
sortCol1: function(e) {
...