0
\$\begingroup\$

This is my first day coding, and I need help with sorting a table in ascending/descending order. The idea is that when a column is clicked it will sort in ascending order, and then it is clicked again it will sort in descending order, then repeat.

This is the function I have created so far.

    /*
    * A function to show sort data.
    */
    function sortTable(n) 
    {
      var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
      table = document.getElementById("usersId");
      switching = true;
      dir = "asc"; 
      while (switching) 
      {
        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;
          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;
          //Each time a switch is done, increase this count by 1:
          switchcount ++;      
        } 
        else 
        {
          if (switchcount == 0 && dir == "asc") {
            dir = "desc";
            switching = true;
          }
        }
      }
    }

Here is a table example

<table id="table">
      <tr>
        <th onclick="sortTable(0)">Number</th>
        <th onclick="sortTable(1)">Fruit</th>
        <th onclick="sortTable(2)">Eater</th>
      </tr>
      <tr>
        <td>2</td>
        <td>Apple</td>
        <td>JeffVeggies</td>
      </tr>
      <tr>
        <td>1</td>
        <td>Grapes</td>
        <td>MattTreeHugger</td>
      </tr>
      <tr>
        <td>3</td>
        <td>Orange</td>
        <td>KevinJuicer</td>
      </tr>
    </table>

I have doubts about the for-loop within the while, but the alternative was nested for-loops. What is the correct, optimal way of sorting?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

You don't need a library or to implement your own sort routine. Sorting is built into arrays.

document.getElementById("usersId").rows.sort((a, b) => {
  aInner = a.getElementsByTagName("td")[n].innerHTML.toLowerCase();
  bInner = b.getElementsByTagName("td")[n].innerHTML.toLowerCase();

  return aInner < bInner ? -1 : +(aInner > bInner);
});

Note that there may be better ways to do this in Javascript. For example, you might want to get all your lowercased inner HTML first. I'm not really a Javascript developer, so I'm not going to try to make the most efficient version (look in the documentation under sorting with map). This will be simpler than yours for small tables and vastly more performant for very unsorted large tables (because it's a loglinear sort rather than a quadratic sort).

Comparison function based on the one posted here. Swap a and b in the first line to reverse the direction (I believe that I have it for ascending here).

document.getElementById("usersId").rows.sort((b, a) => {

Opposite direction.

\$\endgroup\$
1
  • \$\begingroup\$ thank you for your answer! I appreciate that. I did not know about the .sort(). But now that you have mentioned it, I am seeing more examples for this problem. I found a stackoverflow thread. Is it a better solution than what you are suggesting? stackoverflow.com/questions/55462632/… \$\endgroup\$ Sep 17, 2021 at 19:44
0
\$\begingroup\$

One gotcha with the string digit comparison is that \$ 1 < 11 < 2\$. To help with that, and a bunch of other gotchas, there is Intl.Collator with its numeric option. Once the table is sorted by column, clicking on the same column doesn’t need to sort again as it would suffice to just reverse() the rows. Semantically, it would be good to markup for the table headers with <thead>, to differentiate it from the body <tbody>.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.