Sort table by HTML5 data value

Sort table by HTML5 data value

ifischerifischer Posts: 6Questions: 1Answers: 1
edited November 2012 in General
I have a table where I'm using the new HTML5 Data Attributes (see http://ejohn.org/blog/html-5-data-attributes/). So my tds contain an additional attribute called data-rawvalue. In my case I'm printing byte values in a human-readable form, but still want to sort them by their raw value (doint the same by string-parsing the content text would not be sufficient here). Also I want to sort IPs that are shown human readable in text and converted to an integer in the rawvalue attribute.

A minimal example:

[code]
<!DOCTYPE html>




@import "css/jquery.dataTables.css";




$(document).ready( function() {
$('#server_list').dataTable();
} );







Name
IP
Total RAM
Disk space




1
server1
10.1.11.239
64.0 GB
36.0 TB


2
server2
10.1.21.206
128.0 GB
18.0 TB





[/code]

Now how can I tell datatables to use the data-rawvalue attribute - and not the text - for sorting the rows?
I already found out that I could also use iDataSort in combination with a hidden column to achieve the same, but I find the HTML5-data approach much more elegant - it keeps my markup clean and doing it this way will become a standard.

Replies

  • allanallan Posts: 63,152Questions: 1Answers: 10,405 Site admin
    Currently this isn't actually possible with DataTables I'm sorry to say. There is a workaround which makes it possible with a live DOM sorting plug-in ( http://datatables.net/development/sorting#data_source ), but that's really rather inefficient.

    This is something that I want to make easy to do in v1.10, although I've not actually determined how to do that just yet (not really looked at it yet - will involve mData and a few internal changes).

    Allan
  • ifischerifischer Posts: 6Questions: 1Answers: 1
    Thanks!
    Until then I'll try to create a workaround which preprocesses my table and adds new (invisible) rows and changes the sorting for all column headers containing a data-format hint. Will post it here if it works and is performant enough.
  • robinsmidsrodrobinsmidsrod Posts: 2Questions: 0Answers: 0
    I've used the following code to create two sTypes named "data-string" and "data-numeric" which uses HTML5 data attribute on a span element to store the sortable value.

    [code]
    /* Read sort value from displayvalue */
    jQuery.extend( jQuery.fn.dataTableExt.oSort, {
    "data-string-pre" : function(el) {
    // force type-conversion to string
    return String( $(el).data('sortValue') );
    },
    "data-string-asc" : function(a, b) {
    return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },
    "data-string-desc": function(a,b) {
    return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    },
    "data-numeric-pre" : function(el) {
    // force type-conversion to number
    return 1 * $(el).data('sortValue');
    },
    "data-numeric-asc" : function(a, b) {
    return ((a < b) ? -1 : ((a > b) ? 1 : 0));
    },
    "data-numeric-desc": function(a,b) {
    return ((a < b) ? 1 : ((a > b) ? -1 : 0));
    }
    } );
    [/code]

    I use this piece of configuration:

    [code]
    "aoColumns" : [
    { "sType" : "data-string" },
    { "sType" : "data-string" }
    ]
    [/code]

    I tried using this code to get the information from the TD instead of from an additional SPAN, but it didn't work, because the cell content is in a document fragment which doesn't have the TD as an ancestor.

    [code]
    "data-string-pre" : function(el) {
    return $(el).closest('td').data('sortValue');
    },
    [/code]
  • allanallan Posts: 63,152Questions: 1Answers: 10,405 Site admin
    Thanks for posting your sorting plug-in - interesting solution! The problem with it that I can see, is that it is heavy on creating and destroying nodes, so its going to be quite slow. No problem for smallish row counts in Chrome etc, but will quickly bog IE9- down I think.

    Allan
  • shibataismshibataism Posts: 1Questions: 0Answers: 0
    I'm new here. First of all, thanks for this awesome library!

    And +1 for HTML 5 data-Attributes. If this is implemented in v1.10, DataTables will get much more easier to show complexed data!

    FYI, there is other one: http://joequery.github.com/Stupid-Table-Plugin/
    I totally understand DataTables is much more powerful!
  • allanallan Posts: 63,152Questions: 1Answers: 10,405 Site admin
    I've got this on my 'to-do' sheet of paper in front of me :-). Still not 100% certain how this should be implemented as there are a number of complications, not the least of which is that any data attribute could be used (custom naming).

    Thanks for the link - that plug-in uses `data-sort` to specify the sorting type - I'd mainly been thinking about using attributes to specify the data to be sorted, but both should be available. There should also be an option to specify sorting direction.

    I think the real trick here is perhaps not so much implementing it, but implementing it in a way that does add several K of code to DataTables...

    This is certainly something I want in 1.10 though.

    Allan
  • robinsmidsrodrobinsmidsrod Posts: 2Questions: 0Answers: 0
    I'd like to share with you the code I've used to initialize DataTables in my app. It is generic and uses mostly HTML5 data attributes for configuration. What it is missing, it the ability to configure sort type and order with html5 data attributes on the THs inside THEAD, and as I mentioned earlier in the thread, the need for an additional span element to put the data-sort-value attribute with the sort value. I'd really like those to be specified on the TDs instead.

    [code]
    /* Initialize jQuery DataTables component on all tagged tables
    * If you try to initialize the same element twice, only first call to init
    * will be performed.
    */
    PORTFOLIO.init_data_tables = function(selector, config) {

    // Make sure jQuery dataTable plugin is loaded and available
    if ( ! $.fn.dataTable ) {
    return null;
    }

    // DOM selector is required
    if ( ! selector ) {
    return null;
    }

    // Make sure selector matches something
    var $el = $(selector);
    if ( ! $el.get(0) ) {
    return null;
    }

    // Ignore element that has already been rendered
    var element_data = $el.data();
    if ( element_data._rendered ) {
    return null;
    }

    // Define some table display defaults that make sense
    var defaults = {
    "oLanguage": {
    "sUrl" : PORTFOLIO.static_url + "jquery/datatables/media/i18n/" + PORTFOLIO.client_language + ".js"
    },
    "bJQueryUI": true, // use jQueryUI themeroller support
    "bPaginate": false, // don't paginate by default
    "bInfo": true, // show totals
    "bFilter": true, // allow searching
    "bSort": true, // enable sorting
    "aaSorting": [], // use server-side sort for initial view
    "aoColumnDefs": [
    { "sType": "data-string", "aTargets": [ "col-text", "col-date" ] },
    { "sType": "data-numeric", "aTargets": [ "col-number" ] },
    { "bSortable": false, "aTargets": [ "col-checkbox", "col-actions" ] },
    { "sType": "html", "aTargets": [ "_all" ] }
    ]
    };

    // Merge defaults, HTML5 table data and specified configuration parameters
    // We can't do a deep copy, because the jQuery merge method actually merges
    // each object element of arrays instead of appending elements to the arrays
    // We also flatten the "tables" key into the base object and delete it, which
    // makes it easy to include a block of JSON in a simple way.
    var dt = jQuery.extend({}, defaults, element_data.tables, element_data, config);
    delete dt.tables;

    // Render table
    var result = $el.dataTable(dt);

    $el.data('_rendered', true);
    return result;
    };
    [/code]

    What I like about this is that I allow just plain HTML5 data attributes, but I also use a spcial attribute called "tables" that is merged with the generic settings. This allows for a lot of flexibility in how you specify global params. You'll notice that my check for already rendered table is a bit crude, and I'd love for a more generic way of doing this.

    I initialize it like this to even move an A element that is supposed to look like a button into the header box. The nice thing about this is that the supplied config is merged with the defaults AND the HTML5 data-attributes to form the total config. I feel that this allows for very fine-grained tuning and overriding for each page, while retaining a global way of doing things for the entire site.

    [code]
    $(document).ready(function() {
    PORTFOLIO.init_data_tables('table.display', {
    "fnDrawCallback": function( oSettings ) {
    var wrapper = oSettings.nTableWrapper;
    var $toolbar = $('.ui-toolbar:first', wrapper);
    var $button = $(wrapper).parent().find('a.button');
    $button.prependTo($toolbar);
    return true;
    }
    });
    });
    [/code]

    The HTML itself looks like this (with embedded Perl Template Toolkit markup so you can see how I go about it):

    [code]
    [% FOREACH period IN aggregates -%]
    [% IF loop.first -%]

    [% title %]
    My action button inside dataTables header



    [% i18n('Period started') %]
    [% i18n('Week') %]
    [% i18n('Time spent') %]
    [% i18n('Page views') %]
    [% i18n('Interactivity') %]



    [% END -%]



    [% human_date(period.period_started_at, '%A %d. %b %Y') %]



    [% human_date(period.period_started_at,'%V') %]

    [% period.time_spent %]
    [% period.page_view_count %]
    [% period.interactivity %]

    [% IF loop.last -%]



    [% END -%]
    [% END -%]
    [/code]

    As you can see, there are several things going on here, and I still don't have data attributes on the THs to set sort-type and order (I use CSS classes for now), and the col-number sType doesn't look at the table text if the html5 data attribute is not present (which is stupid and should be fixed so it falls back). But overall it works well and so far I've had no problems with speed, even on tables that contain more than 4000 rows (though, they did use pagination with 100 rows per page) in the server-side HTML.

    Allan, I hope this can give you some ideas on how to approach things in a backward-compatible way.

    PS: The paramter bJQueryUI is not very easy to specify with the HTML5 data-attribute camel-casing rules. That's why I had to go with embedded JSON. Do tell me if you figure out how to name it in accordance with the W3C rules.
This discussion has been closed.