My Technical Notes

Thursday, 27 March 2014

DataTables Sorting Function

DataTables automatically detects the types of columns and sorts according to the detected type, which is usually string. Tapping into the detection mechanism is convenient because it saves you from having to manually specify the type of each column.

I defined sorting for two types:

  • UK Date - a date written in UK Format. For example 01/05/2010 which is 1st of May, 2010 (NOT 5th of January).
  • Integer Link - a link which displays an integer ID. For example: 210.

Firstly, I defined a function addType onto jQuery.fn.dataTableExt which takes an options object with these parameters:

  • name - the name of the type.
  • detect - a function which can detect if a value is of that type. For the UK Date, if I passed in 'xkxjdlj' then it should return false, and if I passed in a correct UK date, like '03/12/1997', it should return true.
  • compare - a function that takes two arguments, x and y, and compares them, much like the IComparer<T> interface of the .NET Framework. If x is less than y, we return a negative number, if x is greater than y return a positive number, and if they are equal, return 0.

Here is the definition of jQuery.fn.dataTableExt.addType:


jQuery.extend(jQuery.fn.dataTableExt, {
    addType: function (options) {
        var optionsSpecified = options != null && options.name && options.detect && options.compare;
        if (!optionsSpecified) {
            alert('addColumnType: options are not specified correctly.');
        } else {
            this.aTypes.unshift(function (sData) {
                return options.detect(sData) ? options.name : null;
            });

            this.oSort[options.name + '-asc'] = function (x, y) {
                return options.compare(x, y);
            };

            this.oSort[options.name + '-desc'] = function (x, y) {
                return options.compare(x, y) * -1;
            };
        }
    }
});

No onto the UK date type. To detect if it is a valid UK date, we convert it to a Date object and then call .getTime() which should return an integer. If it returns NaN then we know it isn't a UK Date. For example, 'ejelje' won't be a valid date, but '01/08/2012' will be a valid date. To compare them against each other, we just call .getTime() on the date object, which will give us an integer timestamp, which we subtract. Here is the definition:


(function () {
    function parseUkDate(dateStr) {
        dateStr = dateStr.split("/");
        return new Date(dateStr[2], dateStr[1] - 1, dateStr[0]);
    };
                
    jQuery.fn.dataTableExt.addType({
        name: 'uk-date',
        detect: function (sData) {
            return !isNaN(parseUkDate(sData).getTime());
        },
        compare: function (x, y) {
            return parseUkDate(x) - parseUkDate(y);
        }
    });
})();

Note that I have used an anonymous function block so that an inner functions such as parseUkDate are not given global scope.

Now we deal with the parsing of Integer Links. To detect that it is an integer link type, we first check that it is a link (anchor tag), and then we check that the inner text of the link is parseable as an integer. To compare two links, we integer parse the inner text of the link, and then subtract them. Here is the definition:


(function () {
    var linkRegex = new RegExp("^<a.*>([0-9]+)</a>$");

    function parseIntLink(sData) {
        var result = linkRegex.exec(sData);
        return result == null ? NaN : parseInt(result[1], 10);
    }

    jQuery.fn.dataTableExt.addType({
        name: 'int-link',
        detect: function (sData) {
            return !isNaN(parseIntLink(sData));
        },
        compare: function (x, y) {
            return parseIntLink(x) - parseIntLink(y);
        }
    });
})();

No comments: