jQuery DataTables numeric ordering in column containing hidden HTML

4

By using jQuery DataTables , we can indicate the desired sort order :

$('#example').dataTable( {
  "aoColumnDefs": [
    { "sType": "numeric", "aTargets": [ 0 ] }
  ]
});

But if HTML is present, hidden or not, the sort order of numeric stops working:

var oTable = $("#products").dataTable({
  "aaData": [
    [1, "Dinner", "<span>? 1</span>1"],
    [2, "Study", "<span>? 54</span>54"],
    [2, "Study", "<span>? -5</span>-5"],
    [3, "Sleep", "<span>? 6</span>6"],
    [4, "Sleep", "<span> ?</span>"],
    [5, "Sleep", "<span>3 ?</span>3"],
    [6, "Study", "<span>? 60</span>60"]
  ],
  "aoColumns": [{
    "sClass": "center",
    "bSortable": false
  }, {
    "sClass": "center",
    "bSortable": false
  }, {
    "sClass": "center",
    "bSortable": true,
    "sType": "numeric"
  }]
});
tr.row_selected td {
  background-color: red !important;
}
td > span {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><linkhref="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css" rel="stylesheet" />
<script src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script><divid="table_container">
  <table id="products">
    <thead>
      <tr>
        <th>id</th>
        <th>name</th>
        <th>quantity</th>
      </tr>
    </thead>
    <tbody></tbody>
  </table>
</div>

Demonstration of the problem also in JSFiddle .

The problem here is that% hidden% is required to provide additional functionality in the table, but it may not be obstructing the ordering of the data in each column.

Question

How do I sort a column whose cells contain hidden HTML?

    
asked by anonymous 20.12.2014 / 18:26

1 answer

4

Effectively, the ordering is based on the content of the cells, so even hidden, the HTML present in the cell will make it impossible to sort the number numerically.

The solution in these cases is to create an auxiliary function to sort the desired column (s).

For this purpose, DataTables allows you to expand your structure to apply a custom function for ascending and descending ordering which has its effect on the value passed in the parameter sType :

jQuery.fn.dataTableExt.oSort["meuValorSType-desc"] = function (x, y) {
    // código aqui
};

jQuery.fn.dataTableExt.oSort["meuValorSType-asc"] = function (x, y) {
    // código aqui
}


Solution

To sort numerically, and using the values presented in the question example, there are some considerations to take:

  • Remove HTML
  • Watch out for negative numbers
  • Be aware of empty values

DataTables gives us two parameters, above represented by x and y , which contain the values of the cells:

console.log(x);   // retorna: <span>? 54</span>54

As we have HTML in the value of the cell, and within that HTML the same value visible in the cell on which we want to perform the ordering, we can pass the same to an object:

console.log($(x));   // retorna: Object[span]

Where then making use of the method .text() of jQuery we get only with its contents:

console.log($(x).text());   // retorna: ? 54

Then we have to remove the ? and white space where for the effect we use a regular expression that aims to leave only digits and the sign - , which we use in the .replace() will return only the values we want to preserve:

console.log($(x).text().replace(/[^0-9.-]/g, ""));   // retorna: 54

Now that we have the value of the cell, we need to be aware of the fact that it is empty:

if (!meuValor) {
  // está vazio, aplicar lógica adequada
}

Putting all this together and applying to the parameter represented by x and y :

// instancia variáveis com X e Y apenas com o número na célula
var myX = $(x).text().replace(/[^0-9.-]/g, ""),
    myY = $(y).text().replace(/[^0-9.-]/g, "");

// Se o X está vazio, atribui um valor negativo super elevado
// cujo mesmo sabemos nunca vir a ser utilizado nas células
if (!myX) myX = -9999999999999;

// Se o X está vazio, atribui um valor negativo super elevado
// cujo mesmo sabemos nunca vir a ser utilizado nas células
if (!myY) myY = -9999999999999;

Now that we have the logic ready, we can apply the same in our custom ordering functions:

/* Função para ordenação descendente para colunas com o sType="meuValorSType"'
 */
jQuery.fn.dataTableExt.oSort["meuValorSType-desc"] = function (x, y) {
    var myX = $(x).text().replace(/[^0-9.-]/g, ""),
        myY = $(y).text().replace(/[^0-9.-]/g, "");
    if (!myX) myX = -9999999999999;
    if (!myY) myY = -9999999999999;

    // Devolve à DataTables o resultado de X-Y para ela saber qual o menor dos dois
    return myX - myY;
};

/* Função para ordenação ascendente para colunas com o sType="meuValorSType"'
 */
jQuery.fn.dataTableExt.oSort["meuValorSType-asc"] = function (x, y) {

    // Não precisamos repetir código, chamamos a ordenação descendente
    // mas trocamos os valores de entrada.
    return jQuery.fn.dataTableExt.oSort["meuValorSType-desc"](y, x);
}


Example

Now that we've seen how to resolve the issue, let's apply it all to the present code in the question:

Example also in the JSFiddle .

jQuery.fn.dataTableExt.oSort["myNumeric-desc"] = function(x, y) {
  var myX = $(x).text().replace(/[^0-9.-]/g, ""),
    myY = $(y).text().replace(/[^0-9.-]/g, "");
  if (!myX) myX = -9999999999999;
  if (!myY) myY = -9999999999999;
  return myX - myY;
};

jQuery.fn.dataTableExt.oSort["myNumeric-asc"] = function(x, y) {
  return jQuery.fn.dataTableExt.oSort["myNumeric-desc"](y, x);
}

var oTable = $("#products").dataTable({
  "aaData": [
    [1, "Dinner", "<span>? 1</span>1"],
    [2, "Study", "<span>? 54</span>54"],
    [2, "Study", "<span>? -5</span>-5"],
    [3, "Sleep", "<span>? 6</span>6"],
    [4, "Sleep", "<span> ?</span>"],
    [5, "Sleep", "<span>3 ?</span>3"],
    [6, "Study", "<span>? 60</span>60"]
  ],
  "aoColumns": [{
    "sClass": "center",
    "bSortable": false
  }, {
    "sClass": "center",
    "bSortable": false
  }, {
    "sClass": "center",
    "bSortable": true,
    "sType": "myNumeric"
  }]
});
tr.row_selected td {
  background-color: red !important;
}
td > span {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><linkhref="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css" rel="stylesheet" />
<script src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script><divid="table_container">
  <table id="products">
    <thead>
      <tr>
        <th>id</th>
        <th>name</th>
        <th>quantity</th>
      </tr>
    </thead>
    <tbody></tbody>
  </table>
</div>
    
20.12.2014 / 21:33