Search code examples
javascripthtmlfilterinnerhtml

Sorting number in HTML Table


With the help of W3Schools, I tried to create a filter for sorting Marks from ascending to descending and vice versa.

But it is not sorting. And it seems there's an error somewhere at: getElementsByTagName("SPAN").innerHTML but I am not able to solve it.

Also, After sorting the first column (Sr.) should not change!

function sortTable() {
  var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
  table = document.getElementById("myTable");
  switching = true;
  //Set the sorting direction to ascending:
  dir = "asc";
  /*Make a loop that will continue until
  no switching has been done:*/
  while (switching) {
    //start by saying: no switching is done:
    switching = false;
    rows = table.rows;
    /*Loop through all table rows (except the
    first, which contains table headers):*/
    for (i = 1; i < (rows.length - 1); i++) {
      //start by saying there should be no switching:
      shouldSwitch = false;
      /*Get the two elements you want to compare,
      one from current row and one from the next:*/
      x = rows[i].getElementsByTagName("TD")[2];
      y = rows[i + 1].getElementsByTagName("TD")[2];
      /*check if the two rows should switch place,
      based on the direction, asc or desc:*/
      if (dir == "asc") {
        if (Number(x.getElementsByTagName("SPAN").innerHTML) > Number(y.getElementsByTagName("SPAN").innerHTML)) {
          shouldSwitch = true;
          break;
        }
      } else if (dir == "desc") {
        if (Number(y.getElementsByTagName("SPAN").innerHTML) > Number(x.getElementsByTagName("SPAN").innerHTML)) {
          shouldSwitch = true;
          break;
        }
      }
    }
    if (shouldSwitch) {
      /*If a switch has been marked, make the switch
      and mark that a switch has been done:*/
      rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
      switching = true;
      //Each time a switch is done, increase this count by 1:
      switchcount++;
    } else {
      /*If no switching has been done AND the direction is "asc",
      set the direction to "desc" and run the while loop again.*/
      if (switchcount == 0 && dir == "asc") {
        dir = "desc";
        switching = true;
      }
    }
  }
}
table {
  border-spacing: 0;
  width: 100%;
  border: 1px solid #ddd;
}

th,
td {
  text-align: left;
  padding: 16px;
}

tr:nth-child(even) {
  background-color: #f2f2f2
}
<p><button onclick="sortTable()">Sort</button></p>

<table id="myTable">
  <tr>
    <th>Sr</th>
    <th>Name</th>
    <th>Marks</th>
  </tr>
  <tr>
    <td class="font-elephant">1</td>
    <td class="font-elephant">John</td>
    <td class="font-elephant"><span>438</span> Passed</td>
  </tr>
  <tr>
    <td class="font-elephant">2</td>
    <td class="font-elephant">Kevin</td>
    <td class="font-elephant"><span>238</span> Failed</td>
  </tr>

  <tr>
    <td class="font-elephant">3</td>
    <td class="font-elephant">Lux</td>
    <td class="font-elephant"><span>568</span> Passed</td>
  </tr>

  <tr>
    <td class="font-elephant">4</td>
    <td class="font-elephant">Bro</td>
    <td class="font-elephant"><span>538</span> Passed</td>
  </tr>

</table>

But it is not sorting. And it seems there's an error somewhere at: getElementsByTagName("SPAN").innerHTML but I am not able to solve it.

Also, After sorting the first column (Sr.) should not change!


Solution

  • Here is my solution: first extract the value of eachspan element then sort them with Array.prototype.sort and then reinsert them to your DOM.

    let ORDERED = false;
    
    function sortTable() {
      // Get DOM nodes
      const nodes = document.querySelectorAll("#myTable tr");
      // Create JS array
      const arr = Array.from(nodes);
      // Remove first row (title)
      arr.splice(0, 1);
      // Create array of objects {node: DOMNode, value: number}
      // Then sort with Array.prototype.sort which takes a callback argument
      let sorted = arr.map(node => ({
          node,
          value: parseInt(node.querySelectorAll(".font-elephant")[0].innerHTML)
        }))
        .sort((a, b) => (a.value > b.value) ? 1 : -1);
      if(ORDERED) {
          sorted = sorted.reverse();
          ORDERED = false;
      }
      else ORDERED = true;
      // Get table node to append elements to
      const table = document.querySelector("#myTable");
      sorted.forEach(({
        node
      }) => table.appendChild(node));
    }
    
    document.querySelector("#sortButton").addEventListener("click", sortTable);
    table {
      border-spacing: 0;
      width: 100%;
      border: 1px solid #ddd;
    }
    
    th,
    td {
      text-align: left;
      padding: 16px;
    }
    
    tr:nth-child(even) {
      background-color: #f2f2f2;
    }
    <p><button id="sortButton">Sort</button></p>
    
    <table id="myTable">
      <tr>
        <th>Sr</th>
        <th>Name</th>
        <th>Marks</th>
      </tr>
      <tr>
        <td class="font-elephant">1</td>
        <td class="font-elephant">John</td>
        <td class="font-elephant"><span>438</span> Passed</td>
      </tr>
      <tr>
        <td class="font-elephant">2</td>
        <td class="font-elephant">Kevin</td>
        <td class="font-elephant"><span>238</span> Failed</td>
      </tr>
    
      <tr>
        <td class="font-elephant">3</td>
        <td class="font-elephant">Lux</td>
        <td class="font-elephant"><span>568</span> Passed</td>
      </tr>
    
      <tr>
        <td class="font-elephant">4</td>
        <td class="font-elephant">Bro</td>
        <td class="font-elephant"><span>538</span> Passed</td>
      </tr>
    
    </table>