Datatables sort column by price

Viewed 38

I have a table like:

<table id="myTable">
    <thead>
        <tr>
            <th>Name</th>
            <th>Surname</th>
            <th>Salary</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Julie</td>
            <td>Brown</td>
            <td><span title="Salary" data-html="true" data-toggle="tooltip">2356,70€</span></td>
        </tr>
        <tr>
            <td>Carol</td>
            <td>Miller</td>
            <td><span title="Salary" data-html="true" data-toggle="tooltip">1356,70€</span></td>
        </tr>
        <tr>
            <td>Anna</td>
            <td>Taylor</td>
            <td><span title="Salary" data-html="true" data-toggle="tooltip">356,70€</span></td>
        </tr>
    </tbody>
</table>

And the following javascript code:

$('#myTable')
    .addClass('nowrap')
    .dataTable({
        responsive: true,
        pagingType: "full_numbers",
        lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "Tots"]],
        pageLength: -1,
        columnDefs: [
            {
                "type": "num-fmt",
                targets: 2
            }
        ]
    });

The ASC order must be Anna, Carol, Julie, But I get Carol, Julie Anna, the table is not sorting properly the salary column. It sorts as string not as number.

Can someone help me with this, please?

Kind regards

1 Answers

Instead of type: "num-fmt" use type: "html-num-fmt" - because your Salary column contains your currency amounts inside additional HTML - the <span> tag.

Demo:

$(document).ready(function() {

$('#myTable')
    .addClass('nowrap')
    .dataTable({
        responsive: true,
        pagingType: "full_numbers",
        lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "Tots"]],
        pageLength: -1,
        columnDefs: [
            {
                "type": "html-num-fmt",
                targets: 2
            }
        ]
    });

} );
<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Demo</title>
  <script src="https://code.jquery.com/jquery-3.5.0.js"></script>
  <script src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.js"></script>
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.12.1/css/jquery.dataTables.css">
  <link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">

</head>

<body>

<div style="margin: 20px;">

    <table id="myTable">
    <thead>
        <tr>
            <th>Name</th>
            <th>Surname</th>
            <th>Salary</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Julie</td>
            <td>Brown</td>
            <td><span title="Salary" data-html="true" data-toggle="tooltip">2356,70€</span></td>
        </tr>
        <tr>
            <td>Carol</td>
            <td>Miller</td>
            <td><span title="Salary" data-html="true" data-toggle="tooltip">1356,70€</span></td>
        </tr>
        <tr>
            <td>Anna</td>
            <td>Taylor</td>
            <td><span title="Salary" data-html="true" data-toggle="tooltip">356,70€</span></td>
        </tr>
    </tbody>
</table>

</div>



</body>
</html>

The DataTables documentation for column types describes the difference:

num-fmt - Numeric sorting of formatted numbers.

html-num-fmt - As per the num-fmt option, but with HTML tags also in the data.


It's also worth noting that all these different column types can be auto-detected by DataTables:

DataTables has a number of built in types which are automatically detected...

Therefore in your case, you do not even need that columnDefs option. It can be removed.


Update

"if I type "1.356,70€" instead of "1356,70€", it still doesn't work"

To have more control over how the data is displayed, sorted, and filtered, you can use DataTables' support for orthogonal data.

This is where you can define different values to be used for displaying, sorting and filtering.

Here is an example:

columnDefs: [
  {
    targets: 2,
    render: function (data, type, row) {
      if ( type === 'sort' ) {
        return data.replace( /<[\s\S]*?>/g, "" ).replace(/[.€]/g, "");
      } else if ( type === 'filter' ) {
        return data.replace( /<[\s\S]*?>/g, "" );
      } else {
        return data; // display value
      }
    }
  }
]

How this works: The render function processes each value in the column multiple times (once for each different "type" it can store).

For the sort value:

We first strip out all your HTML using /<[\s\S]*?>/g, and then we remove the thousands separator (.) and the Euro currency sign. This leaves us with text containing only the sortable number.

For the filter value:

We only remove the HTML. This leaves us with the currency text. If we did not remove the HTML from the filter value, then any time we tried to filter on text which happens to also be in the <span> tag, then we would find that row.

For the display value:

We just use the raw input data - everything inside the <td> tag. This means the display will appear to be formatted as we want, using the <span> tag, and will include all that tag's attributes.

So, the user sees what you want them to see. But when data is sorted (or filtered) then these additional values will be used instead of the raw data.

Related