11

I am using jquery.datatables to show numbers in datatables columns. Numbers are formatted to have spaces in between thousands unit (like 123 456 789). Unfortunately, this number formatting provoques a string sorting instead of a number sorting (see the screenshot at the end of this question).

I have identified that:

  • function _fnSort(oSettings, bApplyClasses) { is the core function for sorting.
  • In this function, the dynamic function sorting approach is used (the one executed if if (!window.runtime) { is true)
  • The string sorting functions used are the two following functions.

    /*
    * text sorting
    */
    "string-asc": function(a, b) {
        var x = a.toLowerCase();
        var y = b.toLowerCase();
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    },
    
    "string-desc": function(a, b) {
        var x = a.toLowerCase();
        var y = b.toLowerCase();
        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
    },
    

My knowledge in javascript is pretty poor, what would be the best approach here?

  1. Tweak the string sorting function to detect the number thousands formatted case, and do the comparison (I guess this would be pretty slow on large data set).
  2. Provide a numerical sorting function dedicated for number thousands formatted? In that case
    • how would you code that?
    • how could I indicate to the core sorting function, to use this special numerical sorting function?

Here is what the sorting look like by now:

enter image description here

4 Answers 4

10

To sort this kind of values, you can use this sort function :

var sortFunction=function(a, b)​{
    var ia = parseInt(a.split(' ').join(''), 10);
    var ib = parseInt(b.split(' ').join(''), 10);
    return ia-ib;
};

Test :

var data = ['3 333', '100 333', '22 000', '1 333'];
console.log(data.sort(sortFunction));

With a reasonable number of values, this will be fast enough. You shouldn't try to enrich the data if you don't detect performance problems.

EDIT :

In fact, the documentation proposes an appropriate (similar) sorting function :

jQuery.extend( jQuery.fn.dataTableExt.oSort, {
    "formatted_numbers-pre": function ( a ) {
        a = (a==="-") ? 0 : a.replace( /[^\d\-\.]/g, "" );
        return parseFloat( a );
    },

    "formatted_numbers-asc": function ( a, b ) {
        return a - b;
    },

    "formatted_numbers-desc": function ( a, b ) {
        return b - a;
    }
} );

After having added this extension, you just have to set the sType of your column.

Sign up to request clarification or add additional context in comments.

5 Comments

Awesome! But then how could I force _fnSort() to use this sorting function for the concerned column?
Author of DataTables here - nice answer - up voted. I'd suggest marking as correct/accepted :-). Only typo is the sType as an uppercase 'T': datatables.net/ref#sType . Also worth pointing out that there are lots of other sorting plug-ins (some with type detection counterparts) - datatables.net/plug-ins/sorting
Hi. Sorry for the typo, now fixed.
Great! I'll try this this afternoon and will let you know :)
Ok, I stumble on another issue: how to "set the sType of my column". I can see the javascript code in the section of the doc "How to use DataTables plug-in sorting functions functions (type based)". How can I use this javascript code if I have plenty of dataTable defined in my html? Ideally I'd imagine something like <thead><th sType="numeric2">XX</th></thead>
0

Ok, after a lot of search, I found an alternative solutions. The solution proposed by dystroy and Allan Jardine is certainly cleaner. But it implies touching the HTML and in my case, touching the HTML provoked tricky message box like this one below.

enter image description here

So my solution is to just touch the javascript string sorting algo, to switch between the numeric and textual cases. I wish it could be cleaner by using something like isDigit(sa.charAt[0]) but it just don't work despite all my attempts. At least this solution works and doesn't imply any noticeable performance cost:

    /*
    * text + integer sorting
    */
    "string-asc": function(a, b) {
       var sa = a.toString();
       if(sa.length > 0) {
          // Don't know why, isDigit(sa.charAt[0]) doesn't work??
          var ca = sa.substring(0,1);
          if(ca === "0" || ca === "1" || ca === "2" || ca === "3" || ca === "4" || ca === "5" || ca === "6" || ca === "7" || ca === "8" || ca === "9") {
             var x1 = parseInt(a.split(' ').join(''), 10);
             var y1 = parseInt(b.split(' ').join(''), 10);
             return x1 - y1;
          }
       }
       var x = a.toLowerCase();
       var y = b.toLowerCase();
       return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    },

    "string-desc": function(a, b) {
        var sa = a.toString();
        if(sa.length > 0) {
           var ca = sa.substring(0,1);
           if(ca === "0" || ca === "1" || ca === "2" || ca === "3" || ca === "4" || ca === "5" || ca === "6" || ca === "7" || ca === "8" || ca === "9") {
              var x1 = parseInt(a.split(' ').join(''), 10);
              var y1 = parseInt(b.split(' ').join(''), 10);
              return y1 - x1;
           }
        }
        var x = a.toLowerCase();
        var y = b.toLowerCase();
        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
    },

Comments

0

To anyone that is reading this and want the complete answer for space between numbers :

  jQuery.extend( jQuery.fn.dataTableExt.oSort, {
      "formatted_numbers-pre": function ( a ) {
        a = (a===" ") ? 0 : a.replace( /[^\d\-\.]/g, "" );
        return parseFloat( a );
      },

      "formatted_numbers-asc": function ( a, b ) {
        return a - b;
      },

      "formatted_numbers-desc": function ( a, b ) {
        return b - a;
      }
  } );

    $('.myTable').DataTable({
      "columnDefs": [
        { "type": "formatted_numbers", "targets": 4 }
      ],
    });
  }

Comments

0

Simply set decimal point when building the DataTable like this:

var main_table = $('#main_list').DataTable({
    ajax: {
        url: "/api/your/data",
        dataSrc: ''
    },
    columns: [
        { data: "Col1" },
        { data: "Col2" },
        { data: "Col3" },
        { data: "Col4" }
    ],
    language: {
        /* -----> */ "decimal": ",", // <---------
        "emptyTable": "Keine Daten in der Tabelle verfügbar",
        "info": "Anzeigen von _START_ bis _END_ von _TOTAL_ Einträgen",
        "infoEmpty": "Anzeigen von 0 bis 0 von 0 Einträgen",
        "infoFiltered": "(filtriert von_MAX_ Gesamteinträge)",
        "infoPostFix": "",
        /* -----> */ "thousands": ".", // <---------
        "lengthMenu": "_MENU_ Einträge anzeigen",
        "loadingRecords": "Laden...",
        "processing": "Verarbeitung...",
        "search": "Suche:",
        "zeroRecords": "Keine passenden Datensätze gefunden",
        "paginate": {
            "first": "Erste",
            "last": "Letzte",
            "next": "Nächste",
            "previous": "Vorherige"
        },
        "aria": {
            "sortAscending": ": aufsteigend sortieren",
            "sortDescending": ": absteigend sortieren"
        }
    },
    columnDefs: [
        {//set german formatting

            render: function (data, type, row) {
                return formatDE(data,2);
            },
            targets: [2, 4, 5]
        },
        {

            render: function (data, type, row) {
                return formatDE(data,0);
            },
            targets: [3]
        }
    ],
    pageLength: 50});

If you dig in more into jquery.dataTables.js you will find that they have a function which determines the type of every column value and catches the format

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.