5

I notices that UK date sorting does not work when a date is also a link.

Example 1. (demo)

Here the date is pure test. Works complete fine.

       <tr>
            <td>01/01/01</td>
            <td>Tarik</td>
            <td>Rashad Kidd</td>
            <td>1 34 238 6239-0509</td>
        </tr>

Example 2. (demo)

Here the date is also a link. Does not work at all. Not throwing any errors though.

         <tr>
            <td><a href="#">01/01/01</a></td>
            <td>Tarik</td>
            <td>Rashad Kidd</td>
            <td>1 34 238 6239-0509</td>
        </tr>

I also noticed that the sorting does work on any other elements even if they are a link. Only the date as a link are the issue.

I'm using the following JS code:

// UK Date Sorting
jQuery.fn.dataTableExt.oSort['uk_date-asc']  = function(a,b) {
    var ukDatea = a.split('/');
    var ukDateb = b.split('/');

    var x = (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
    var y = (ukDateb[2] + ukDateb[1] + ukDateb[0]) * 1;

    return ((x < y) ? -1 : ((x > y) ?  1 : 0));
};

jQuery.fn.dataTableExt.oSort['uk_date-desc'] = function(a,b) {
    var ukDatea = a.split('/');
    var ukDateb = b.split('/');

    var x = (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
    var y = (ukDateb[2] + ukDateb[1] + ukDateb[0]) * 1;

    return ((x < y) ? 1 : ((x > y) ?  -1 : 0));
}


$(document).ready(function() {

    $('#table').dataTable( {
        "bPaginate": true,
        "bLengthChange": true,
        "bFilter": true,
        "aoColumnDefs" : [
            { "aTargets" : ["uk-date-column"] , "sType" : "uk_date"}
        ]
    });

});

Any help much appreciated.

Iladarsda
  • 10,640
  • 39
  • 106
  • 170

4 Answers4

4

The problem is that you sorting function is confused by the extra html. You should modify your functions like this:

// UK Date Sorting
jQuery.fn.dataTableExt.oSort['uk_date-asc']  = function(a,b) {  
    //use text()
    var ukDatea = $(a).text().split('/');
    var ukDateb = $(b).text().split('/');

    var x = (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
    var y = (ukDateb[2] + ukDateb[1] + ukDateb[0]) * 1;

    return ((x < y) ? -1 : ((x > y) ?  1 : 0));
};

jQuery.fn.dataTableExt.oSort['uk_date-desc'] = function(a,b) {
    //use text()
    var ukDatea = $(a).text().split('/');
    var ukDateb = $(b).text().split('/');

    var x = (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
    var y = (ukDateb[2] + ukDateb[1] + ukDateb[0]) * 1;

    return ((x < y) ? 1 : ((x > y) ?  -1 : 0));
} 

fiddle here http://jsfiddle.net/GUb2n/

Nicola Peluchetti
  • 76,206
  • 31
  • 145
  • 192
  • Thanks! Can you just explain what have you change and why? Much appreciated! – Iladarsda Mar 13 '12 at 09:26
  • 1
    @NewUser i used `var ukDatea = $(a).text().split('/');` instead of `var ukDatea = a.split('/');`. in this way the date can be split correctly because you are getting only the text of the link and not the markup – Nicola Peluchetti Mar 13 '12 at 09:30
  • Nice! Very simple and straight forward solution. Thanks! – Iladarsda Mar 13 '12 at 09:34
3

You can try to put the date (in ISO Format) in an invisible container in front of the link:

<span style="display: none;">2001-01-01</span><a href="#">01/01/01</a>

Then alphabetic sort should work.

wessnerj
  • 152
  • 2
  • 8
  • lol - this actually works perfectly! simple and elegant! I actually put the hidden date using (strtotime($date)) to get the number version - which is sorted automatically – Laurence Dec 20 '12 at 11:30
  • This is the simplest and quickest solution. Thanks a lot. – Christopher Sep 04 '16 at 02:54
2

IIRC, improper sorting of linkified data has to do with the way DataTables attempts to strip HTML from the content of a table cell (using a simplified regexp) which seems unable to completely extract date data from the cell.

DataTables 1.10+ can use HTML 5 data attributes to avoid this problem.

If you have a link in a set of <td> tags, like this:

<td><a href = "someobject">28 July 2015</a></td>

you can add a data-order attribute to your <td> tag:

<td data-order="2015-07-28"><a href = "someobject">28 July 2015</a></td>

This data-order attribute lets DataTables sort on the data-order attribute and use the content between your <td> tags as display data only.

MarsAtomic
  • 10,436
  • 5
  • 35
  • 56
0

(v1.9.4) This solution not only fixes your sorting woes but also fixes filtering issues because normally the filter matches against the HTML, so searching for things like href or divend up matching all the rows.

It strips away the HTML inside the mRender option and then caches the result since DataTables runs the mRender function multiple times.

JsFiddle Example

Warning for Editable Tables

An editable table may have issues due to the Caching mechanism.

Step1

Include the following javascript somewhere:

var stripHtml = (function() {
    var tmpDiv = document.createElement("DIV");
    return function(html) {
        tmpDiv.innerHTML = html;
        return $.trim(tmpDiv.textContent || tmpDiv.innerText);
    };
})();

var mRenderFactory = function (colIndex) {
    return function (data, type, full) {
        var cache = MRenderCache.getCache(full);

        if (type === "filter" || type === "sort" || type === "type") {
            return cache.getOrElse(colIndex, data, stripHtml)
        }
        return data;
    };
};

var MRenderCache = function () {
    this.full = [];
}
MRenderCache.getCache = function (full) {
    var cache = full[full.length - 1];
    if (cache == null || !cache.MRenderCache) {
        cache = new MRenderCache();
        full.push(cache);
    }
    return cache;
}
MRenderCache.prototype.MRenderCache = true;
MRenderCache.prototype.getOrElse = function (colIndex, rawData, convert) {
    var result = this.full[colIndex];
    if (result === undefined) {
        result = convert(rawData);
        this.full[colIndex] = result;
    }
    return result;
}

Step 2

Set "mRender": mRenderFactory(i) inside aoColumns on any columns you want the HTML stripped where i is the index of the column. It is VERY important you get the right i because if you don't then the table will display fine but will sort and filter on the wrong column.

You're initialization code would look something like this:

$(document).ready(function() {
    $('#example').dataTable( {
        "aoColumns": [
            null,
            null,
            { "mRender": mRenderFactory(2) },
            { "mRender": mRenderFactory(3) },
            null
        ]
    } );
} );
sparebytes
  • 12,546
  • 3
  • 21
  • 32