javascripthtmltab-ordering

I have difficulty ordering a table by letters AND numbers


I have found a very useful script on W3 schools to order tables by ascending or descending order, the problem is I can make it work for one or the other only.

I'm trying to sort "both" depending on what the values in the columns are.

<!DOCTYPE html>
<html>
<head>
<title>Sort a HTML Table Alphabetically</title>
<style>
table {
  border-spacing: 0;
  width: 100%;
  border: 1px solid #ddd;
}

th {
  cursor: pointer;
}
h1{
 color: green;
 }
th, td {
  text-align: left;
  padding: 16px;
}

tr:nth-child(even) {
  background-color: #f2f2f2
}
</style>
</head>
<body>

<h1>WORKS WITH LETTERS</h1>
<h1>WORKS WITH LETTERS</h1>
<h1>WORKS WITH LETTERS</h1>
<table id="myTable">
  <tr>
   <!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->  
    <th onclick="sortTable(0)">Name</th>
    <th onclick="sortTable(1)">Value</th>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>46</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>34</td>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>32</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>432</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>5</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>463</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>1</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>64</td>
  </tr>
</table>

<script>
function sortTable(n) {
  var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
  table = document.getElementById("myTable");
  switching = true;
  dir = "asc"; 
  while (switching) {
    switching = false;
    rows = table.rows;
    for (i = 1; i < (rows.length - 1); i++) {
      shouldSwitch = false;
      x = rows[i].getElementsByTagName("TD")[n];
      y = rows[i + 1].getElementsByTagName("TD")[n];
      if (dir == "asc") {
        if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
          shouldSwitch= true;
          break;
        }
      } else if (dir == "desc") {
        if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
          shouldSwitch = true;
          break;
        }
      }
    }
    if (shouldSwitch) {
      rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
      switching = true;
      switchcount ++;      
    } else {
      if (switchcount == 0 && dir == "asc") {
        dir = "desc";
        switching = true;
      }
    }
  }
}
</script>

</body>
</html>

I can modify this:

if (dir == "asc") {
        if (Number(x.innerHTML) > Number(y.innerHTML)) {
                shouldSwitch = true;
                break;
        }
      } else if (dir == "desc") {
        if (Number(x.innerHTML) < Number(y.innerHTML)) {
                shouldSwitch = true;
                break;
        }
      }

For this:

if (dir == "asc") {
        if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
          shouldSwitch= true;
          break;
        }
      } else if (dir == "desc") {
        if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
          shouldSwitch = true;
          break;
        }
      }

To make it work with numbers, but I can't do both at the same time. I am not sure if I have to create a new table or if i can just indent it, but where?? I am really new to Java as I mainly code with python

Thank you for your help !


Solution

  • You could replace your check with one making use of localeCompare and it's numeric option

    Instead of:

    if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
    

    You could use:

    x = x.innerText.toLowerCase();
    y = y.innerText.toLowerCase();
    
    if (x.localeCompare(y, 'en', {numeric: true}) > 0) {
    

    function sortTable(n) {
      var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
      table = document.getElementById("myTable");
      switching = true;
      dir = "asc";
      while (switching) {
        switching = false;
        rows = table.rows;
        for (i = 1; i < (rows.length - 1); i++) {
          shouldSwitch = false;
          x = rows[i].getElementsByTagName("TD")[n];
          y = rows[i + 1].getElementsByTagName("TD")[n];
          if (dir == "asc") {
            x = x.innerText.toLowerCase();
            y = y.innerText.toLowerCase();
            if (x.localeCompare(y, 'en', {numeric: true}) > 0) {
              shouldSwitch = true;
              break;
            }
          } else if (dir == "desc") {
            x = x.innerText.toLowerCase();
            y = y.innerText.toLowerCase();
            if (x.localeCompare(y, 'en', {numeric: true}) < 0) {
              shouldSwitch = true;
              break;
            }
          }
        }
        if (shouldSwitch) {
          rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
          switching = true;
          switchcount++;
        } else {
          if (switchcount == 0 && dir == "asc") {
            dir = "desc";
            switching = true;
          }
        }
      }
    }
    table {
      border-spacing: 0;
      width: 100%;
      border: 1px solid #ddd;
    }
    
    th {
      cursor: pointer;
    }
    
    h1 {
      color: green;
    }
    
    th,
    td {
      text-align: left;
      padding: 16px;
    }
    
    tr:nth-child(even) {
      background-color: #f2f2f2
    }
    <body>
    
      <h1>WORKS WITH LETTERS</h1>
      <h1>WORKS WITH LETTERS</h1>
      <h1>WORKS WITH LETTERS</h1>
      <table id="myTable">
        <tr>
          <!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
          <th onclick="sortTable(0)">Name</th>
          <th onclick="sortTable(1)">Value</th>
        </tr>
        <tr>
          <td>Berglunds snabbkop</td>
          <td>46</td>
        </tr>
        <tr>
          <td>North/South</td>
          <td>34</td>
        </tr>
        <tr>
          <td>Alfreds Futterkiste</td>
          <td>32</td>
        </tr>
        <tr>
          <td>Koniglich Essen</td>
          <td>432</td>
        </tr>
        <tr>
          <td>Magazzini Alimentari Riuniti</td>
          <td>5</td>
        </tr>
        <tr>
          <td>Paris specialites</td>
          <td>463</td>
        </tr>
        <tr>
          <td>Island Trading</td>
          <td>1</td>
        </tr>
        <tr>
          <td>Laughing Bacchus Winecellars</td>
          <td>64</td>
        </tr>
      </table>
    </body>