knockout js - Table sorting using column headers

html-table, knockout.js

Solution

Here is a quick bindingHandler that you can add to your th's. Upon clicking the th it will sort the column according the property name as defined in the binding.

ko.bindingHandlers.sort = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var asc = false;
        element.style.cursor = 'pointer';

        element.onclick = function(){
            var value = valueAccessor();
            var prop = value.prop;
            var data = value.arr;

            asc = !asc;

            data.sort(function(left, right){
                var rec1 = left;
                var rec2 = right;

                if(!asc) {
                    rec1 = right;
                    rec2 = left;
                }

                var props = prop.split('.');
                for(var i in props){
                    var propName = props[i];
                    var parenIndex = propName.indexOf('()');
                    if(parenIndex > 0){
                        propName = propName.substring(0, parenIndex);
                        rec1 = rec1[propName]();
                        rec2 = rec2[propName]();
                    } else {
                        rec1 = rec1[propName];
                        rec2 = rec2[propName];
                    }
                }

                return rec1 == rec2 ? 0 : rec1 < rec2 ? -1 : 1;
            });
        };
    }
    };

This is a little more elegant in that you don't have to create a separate function for each column. A more complete working example can be found here: http://jsfiddle.net/brendonparker/6S85t/

Problem

I'm new to knockout js & need help workout how to dynamically sort a table using the column header. Following is part of my code: HTML: ``` <table> <thead> <tr data-bind="click: sortFunction"> <th id='id'>Id</th> <th id='name'>Name</th> <th id='description'>Description</th> </tr> </thead> <tbody data-bind="foreach: deptList"> <tr> <td><span data-bind="text: id" /></td> <td><span data-bind="text: name" /></td> <td><span data-bind="text: description" /></td> </tr> </tbody> </table> ``` In my view model I've the following function which I use to sort a data table using the table header. ViewModel: ``` self.deptList = ko.observableArray(mylist); self.sortColumn = ko.observable("id"); self.isSortAsc = ko.observable("True"); var Dept = function(id, name, description) { this.id = ko.observable(id); this.name = ko.observable(name); this.description = ko.observable(description); }; var mylist = [ new Dept(1, "Dept 1", "D1"), new Dept(2, "Dept 2", "D6"), new Dept(3, "Dept 3", "D3"), new Dept(4, "Dept 4", "D4") ]; self.sortFunction = function(data, event) { if (self.sortColum === event.target.id) self.isSortAsc = !self.isSortAsc; else { self.sortColumn = event.target.id; self.isSortAsc = "True"; } self.deptList.sort(function(a, b) { if (self.sortColum === 'id') { if (self.isSortAsc) a.id < b.id ? -1 : 1; else a.name < b.name ? 1 : -1; } else if (self.sortColum === 'name') { if (self.isSortAsc) a.name < b.name ? -1 : 1; else a.name < b.name ? 1 : -1; } else(self.sortColum === 'description') { if (self.isSortAsc) a.description < b.description ? -1 : 1; else a.description < b.description ? 1 : -1; } }); }; ``` Even though above code is working I think there should be a better way to do this (I mean passing the column id as a parameter) which will be useful when there is a large of columns. I tried `left[self.sortColumn] < right[self.sortColumn] ? -1 : 1`, which didn't work as expected. If it is possible to sort via a dynamic column name please show a sample code. Thanks in advance.

Original source