2

Hello i'm using jquery to sort a table on click on the "th" tag, my code working well but only with numbers and words, but not with the date, is there anything wrong in the code :

<table>
  <thead>
    <tr>
      <th>head1</th>
      <th>head2</th>
      <th>head3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>b</td>
      <td>13/03/1998</td>
    </tr>
    <tr>
      <td>3</td>
      <td>a</td>
      <td>02/01/2005</td>
    </tr>
    <tr>
      <td>2</td>
      <td>c</td>
      <td>10/12/2022</td>
    </tr>
  </tbody>
</table>

and the js :

$(document).on('click', 'th', function() {
  var table = $(this).parents('table').eq(0);
  var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()));
  this.asc = !this.asc;
  if (!this.asc) {
    rows = rows.reverse();
  }
  table.children('tbody').empty().html(rows);
});

function comparer(index) {
  return function(a, b) {
    var valA = getCellValue(a, index),
      valB = getCellValue(b, index);
    return $.isNumeric(valA) && $.isNumeric(valB) ?
      valA - valB : valA.localeCompare(valB);
  };
}

function getCellValue(row, index) {
  return $(row).children('td').eq(index).text();
}

thank you in advance

Maryam
  • 146
  • 7

1 Answers1

3

As currently written, your code is treating each date as a string, and sorting it alphanumerically instead of chronologically.

Assuming your dates all use the format dd/mm/yyyy, then you can re-arrange the date strings into a numeric format yyyymmdd, which is suitable for sorting:

function reformatDate(val) {
  return val.substring(6, 10) + val.substring(3, 5) + val.substring(0, 2);
}

You can use this function in your comparer() function, by checking the column index:

if ( index === 2 ) {
  valA = reformatDate(valA);
  valB = reformatDate(valB);
  console.log(valA, valB);
}

A demo:

$(document).on('click', 'th', function() {
  var table = $(this).parents('table').eq(0);
  var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()));
  this.asc = !this.asc;
  if (!this.asc) {
    rows = rows.reverse();
  }
  table.children('tbody').empty().html(rows);
});

function comparer(index) {
  return function(a, b) {
    var valA = getCellValue(a, index),
      valB = getCellValue(b, index);
    if ( index === 2 ) {
      valA = reformatDate(valA);
      valB = reformatDate(valB);
      //console.log(valA, valB);
    }
    return $.isNumeric(valA) && $.isNumeric(valB) ?
      valA - valB : valA.localeCompare(valB);
  };
}

function getCellValue(row, index) {
  return $(row).children('td').eq(index).text();
}

function reformatDate(val) {
  return val.substring(6, 10) + val.substring(3, 5) + val.substring(0, 2);
}
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>demo</title>

<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>

  <style>
  </style>

</head>

<body>

<table>
  <thead>
    <tr>
      <th>head1</th>
      <th>head2</th>
      <th>head3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>b</td>
      <td>13/03/1998</td>
    </tr>
    <tr>
      <td>3</td>
      <td>a</td>
      <td>02/01/2005</td>
    </tr>
    <tr>
      <td>2</td>
      <td>c</td>
      <td>10/12/2022</td>
    </tr>
  </tbody>
</table>


</body>

</html>

This approach takes your constraint "without plugin" to mean without any additional plugins except for jQuery, which is implied by the code in your question.

andrewJames
  • 19,570
  • 8
  • 19
  • 51
  • thank for your help, but my date is not all the times like this : 19/02/2022 it could be also : 12-may-2022 – Maryam May 25 '22 at 14:54
  • In that case, you can (as one example) create another date formatting function to convert that new format to `yyyymmdd`, and then expand the logic in `if ( index === 2 )` to detect when you have each format (e.g. by checking the string length) - and call the relevant function. Research [these questions](https://www.google.com/search?q=javascript+convert+month+to+number+site:stackoverflow.com) for some different approaches regarding the month conversion step. – andrewJames May 25 '22 at 15:51
  • Eventually, if you find you have too many different formats in your source data, you are going to want to use plugins which are designed to make these types of tasks easier to handle. – andrewJames May 25 '22 at 15:51
  • Hi @andrewJames, How to recognize automatically the column type without using index==2 ? – sylvain Mar 23 '23 at 16:21
  • I may have misunderstood your comment... but I would use a plug-in for that - for example, see [DataTables - How to sort by date (dd.mm.yyyy)](https://stackoverflow.com/q/68159588/12567365). The reason I say this: as the requirements become more complex you might find yourself basically [writing a plug-in](https://datatables.net/manual/plug-ins/type-detection#Publish-your-plug-in) for yourself, anyway - so, why not use some code which has already been tested and is widely used? – andrewJames Mar 23 '23 at 16:37
  • If that does not help, you can ask a new question and describe your specific problem with a [mre]. – andrewJames Mar 23 '23 at 16:37