2

I have a table which works by clicking on a header, which then sorts the column in ascending and descending order every time you click on the header. It sorts everything in alphabetical order, but I need it to also be able to sort numerically.

It seems to work until the numbers go beyond single digits within the same column.

This is the HTML code: (Ignore the NFL content, it's just data to test out this table)

<div id="supAll">
            <table border="1" class="supTable">
                <tr> 
                    <th onclick="sortTable('supTable', 0)">Team</th>
                    <th onclick="sortTable('supTable', 1)">SB Wins</th>
                    <th onclick="sortTable('supTable', 2)">SB Losses</th>
                    <th onclick="sortTable('supTable', 3)">Last Won</th>
                </tr>
                <tr class="nfc nfcWest">
                    <td>Arizona Cardinals</td>
                    <td>0</td>
                    <td>1</td>
                    <td>-</td>
                </tr>
                <tr class="nfc nfcSouth">
                    <td>Atlanta Falcons</td>
                    <td>10</td>
                    <td>2</td>
                    <td>-</td>
                </tr>
                <tr class="afc afcNorth">
                    <td>Baltimore Ravens</td>
                    <td>2</td>
                    <td>0</td>
                    <td>2012</td>
                </tr>
                <tr class="afc afcEast">
                    <td>Buffalo Bills</td>
                    <td>11</td>
                    <td>4</td>
                    <td>-</td>
                </tr>
                <tr class="nfc nfcSouth">
                    <td>Carolina Panthers</td>
                    <td>22</td>
                    <td>2</td>
                    <td>-</td>
                </tr>
                <tr class="nfc nfcNorth">
                    <td>Chicago Bears</td>
                    <td>1</td>
                    <td>1</td>
                    <td>1985</td>
                </tr>
                <tr class="afc afcNorth">
                    <td>Cincinnati Bengals</td>
                    <td>0</td>
                    <td>2</td>
                    <td>-</td>
                </tr>
                <tr class="afc afcNorth">
                    <td>Cleveland Browns</td>
                    <td>0</td>
                    <td>0</td>
                    <td>-</td>
                </tr>
                <tr class="nfc nfcEast">
                    <td>Dallas Cowboys</td>
                    <td>5</td>
                    <td>3</td>
                    <td>1995</td>
                </tr>
                <tr class="afc afcWest">
                    <td>Denver Broncos</td>
                    <td>3</td>
                    <td>5</td>
                    <td>2015</td>
                </tr>
                <tr class="nfc nfcNorth">
                    <td>Detroit Lions</td>
                    <td>0</td>
                    <td>0</td>
                    <td>-</td>
                </tr>
                <tr class="nfc nfcNorth">
                    <td>Green Bay Packers*</td>
                    <td>4</td>
                    <td>1</td>
                    <td>2010</td>
                </tr>
                <tr class="afc afcSouth">
                    <td>Houston Texans</td>
                    <td>0</td>
                    <td>0</td>
                    <td>-</td>
                </tr>
                <tr class="afc afcSouth">
                    <td>Indianapolis Colts</td>
                    <td>2</td>
                    <td>2</td>
                    <td>2006</td>
                </tr>
                <tr class="afc afcSouth">
                    <td>Jacksonville Jaguars</td>
                    <td>0</td>
                    <td>0</td>
                    <td>-</td>
                </tr>
                <tr class="afc afcWest">
                    <td>Kansas Chiefs*</td>
                    <td>1</td>
                    <td>1</td>
                    <td>1969</td>
                </tr>
                <tr class="afc afcWest">
                    <td>Los Angeles Chargers</td>
                    <td>0</td>
                    <td>1</td>
                    <td>-</td>
                </tr>
                <tr class="nfc nfcWest">
                    <td>Los Angeles Rams</td>
                    <td>1</td>
                    <td>2</td>
                    <td>1999</td>
                </tr>
                <tr class="afc afcEast">
                    <td>Miami Dolphins</td>
                    <td>2</td>
                    <td>3</td>
                    <td>1973</td>
                </tr>
                <tr class="nfc nfcNorth">
                    <td>Minnesota Vikings</td>
                    <td>0</td>
                    <td>4</td>
                    <td>-</td>
                </tr>
                <tr class="afc afcEast">
                    <td>New England Patriots</td>
                    <td>5</td>
                    <td>4</td>
                    <td>2016</td>
                </tr>
                <tr class="nfc nfcSouth">
                    <td>New Orleans Saints</td>
                    <td>1</td>
                    <td>1</td>
                    <td>2009</td>
                </tr>
                <tr class="nfc nfcEast">
                    <td>New York Giants</td>
                    <td>4</td>
                    <td>1</td>
                    <td>2011</td>
                </tr>
                <tr class="afc afcEast">
                    <td>New York Jets*</td>
                    <td>1</td>
                    <td>0</td>
                    <td>1968</td>
                </tr>
                <tr class="afc afcWest">
                    <td>Oakland Raiders</td>
                    <td>3</td>
                    <td>2</td>
                    <td>1983</td>
                </tr>
                <tr class="nfc nfcEast">
                    <td>Philadelphia Eagles</td>
                    <td>0</td>
                    <td>2</td>
                    <td>-</td>
                </tr>
                <tr class="afc afcNorth">
                    <td>Pittsburgh Steelers</td>
                    <td>6</td>
                    <td>2</td>
                    <td>2008</td>
                </tr>
                <tr class="nfc nfcWest">
                    <td>San Francisco 49ers</td>
                    <td>5</td>
                    <td>5</td>
                    <td>1994</td>
                </tr>
                <tr class="nfc nfcWest">
                    <td>Seattle Seahawks</td>
                    <td>1</td>
                    <td>2</td>
                    <td>2013</td>
                </tr>
                <tr class="nfc nfcSouth">
                    <td>Tampa Bay Buccaneers</td>
                    <td>1</td>
                    <td>0</td>
                    <td>2002</td>
                </tr>
                <tr class="afc afcSouth">
                    <td>Tennessee Titans</td>
                    <td>0</td>
                    <td>1</td>
                    <td>-</td>
                </tr>
                <tr class="nfc nfcEast">
                    <td>Washington Redskins</td>
                    <td>3</td>
                    <td>2</td>
                    <td>1991</td>
                </tr>
            </table>
        </div>      
    </div>

And below here is the Javascript code:

function sortTable(tableClass, n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;

table = document.getElementsByClassName(tableClass)[0];
switching = true;
dir = "asc";
while (switching) {
    switching = false;
    rows = table.getElementsByTagName("TR");
    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;
        }
    }
}

}

If you run the code you can see in the middle column, where there are different sized numbers, it doesn't sort them properly anymore.

Is there any way to use this code/function so that my tables work for sorting both alphabetically and numerically (when it goes above single digits)? And if not can someone please help me solve this problem.

EDIT - This has been solved! If you check out both the code below by Hendeca, and Teldri you will see the solved code. Both of their versions work.

3 Answers 3

13

you should parse the numeric values as integer or float before comparsion

so

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

changes to

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

string comparsion if no number

var cmpX=isNaN(parseInt(x.innerHTML))?x.innerHTML.toLowerCase():parseInt(x.innerHTML);

var cmpY=isNaN(parseInt(y.innerHTML))?y.innerHTML.toLowerCase():parseInt(y.innerHTML);

if (parseInt(cmpX) > parseInt(cmpY)) {

change your function to this:

function sortTable(tableClass, n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;

table = document.getElementsByClassName(tableClass)[0];
switching = true;
dir = "asc";
while (switching) {
    switching = false;
    rows = table.getElementsByTagName("TR");
    for (i = 1; i < (rows.length - 1); i++) {
        shouldSwitch = false;
        x = rows[i].getElementsByTagName("TD")[n];
        y = rows[i + 1].getElementsByTagName("TD")[n];
                var cmpX=isNaN(parseInt(x.innerHTML))?x.innerHTML.toLowerCase():parseInt(x.innerHTML);
                var cmpY=isNaN(parseInt(y.innerHTML))?y.innerHTML.toLowerCase():parseInt(y.innerHTML);
cmpX=(cmpX=='-')?0:cmpX;
cmpY=(cmpY=='-')?0:cmpY;
        if (dir == "asc") {
            if (cmpX > cmpY) {
                shouldSwitch= true;
                break;
            }
        } else if (dir == "desc") {
            if (cmpX < cmpY) {
                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;
        }
    }
}
}
Sign up to request clarification or add additional context in comments.

10 Comments

Hi this works great for sorting out my numerical columns, but it stops me being able to sort my first column alphabetically. Only the numbers can be sorted now.
This works great now thanks! I only have a NEW PROBLEM now..... in some columns I use '-' as a blank to indicate the equivalent to 'N/A', which is obviously not a number. And with any column containing that symbol it doesn't sort it properly. Is there any way around this? Or a way to convert that symbol so it essentially equals 0 (without having to write 0)?
hi there. Just noticed another issue with this code. On some columns i use a '.' before numbers as a percentage indicator e.g. '.600'. On these columns, it won't sort anything. Do you know a way around this?
I've changed the numbers to not have the decimal at the front, but in the middle if it's needed. E.g. '.535' becomes '53.5'. However some numbers are sorted higher/lower than they should. E.G. '48.3' is above '48.6' even though it's a smaller number. Is there a way to fix this?
just use parseFloat() instead of parseInt()
|
2

You need to convert the table cell value to a number if it is a digit and leave it as a string if it is a name. Doing this will make the comparison work for both cases. Here's some updated code:

function sortTable(tableClass, n) {
  var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;

  table = document.getElementsByClassName(tableClass)[0];
  switching = true;
  dir = "asc";
  while (switching) {
      switching = false;
      rows = table.getElementsByTagName("TR");
      for (i = 1; i < (rows.length - 1); i++) {
          shouldSwitch = false;
          x = rows[i].getElementsByTagName("TD")[n];
          y = rows[i + 1].getElementsByTagName("TD")[n];
          var xContent = (isNaN(x.innerHTML)) 
              ? (x.innerHTML.toLowerCase() === '-')
                    ? 0 : x.innerHTML.toLowerCase()
              : parseFloat(x.innerHTML);
          var yContent = (isNaN(y.innerHTML)) 
              ? (y.innerHTML.toLowerCase() === '-')
                    ? 0 : y.innerHTML.toLowerCase()
              : parseFloat(y.innerHTML);
          if (dir == "asc") {
              if (xContent > yContent) {
                  shouldSwitch= true;
                  break;
              }
          } else if (dir == "desc") {
              if (xContent < yContent) {
                  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;
          }
      }
   }
}

By testing to see if the string is a number, you can determine whether to convert that value or not. Here is the pertinent change:

var xContent = (isNaN(x.innerHTML)) ? x.innerHTML.toLowerCase() : parseFloat(x.innerHTML);
var yContent = (isNaN(y.innerHTML)) ? y.innerHTML.toLowerCase() : parseFloat(y.innerHTML);

EDIT: Added some code to handle the case of a - character and converted digit string to float instead of integer to deal with decimal numbers. The new check is:

var xContent = (isNaN(x.innerHTML)) 
        ? (x.innerHTML.toLowerCase() === '-')
            ? 0 : x.innerHTML.toLowerCase()
        : parseFloat(x.innerHTML);
var yContent = (isNaN(y.innerHTML)) 
        ? (y.innerHTML.toLowerCase() === '-')
            ? 0 : y.innerHTML.toLowerCase()
        : parseFloat(y.innerHTML);

6 Comments

This code hasn't worked, I think because of the placing of your change. I think it should be above and outside 'if (dir == "asc") {' If you check out the other answer on this page, that code works and is similar to yours. If you read my latest response I have a new issue...... in some columns I use '-' as a blank to indicate the equivalent to 'N/A', which is obviously not a number. And with any column containing that symbol it doesn't sort it properly. Is there any way around this? Or a way to convert that symbol so it essentially equals 0 (without having to write 0)?
@bevstar7 You're right, it was in the wrong place! I've also added a test to handle the case of a - in a column. This just returns a 0 if it encounters a - for sorting purposes. This code is working for me and handles the - case.
I managed to use the other code to solve my problem (they also solved the '-' issue), but just tried yours and it also works! Thanks for the help.
hi there. Just noticed another issue with this code. On some columns i use a '.' before numbers as a percentage indicator e.g. '.600'. On these columns, it won't sort anything. Do you know a way around this?
I've changed the numbers to not have the decimal at the front, but in the middle if it's needed. E.g. '.535' becomes '53.5'. However some numbers are sorted higher/lower than they should. E.G. '48.3' is above '48.6' even though it's a smaller number. Is there a way to fix this?
|
0

The issue is actually that your numbers are strings. So, '14' is less than '4'. You can try to convert to number first, and if isNaN, then you can test it as a string, otherwise, as a number.

_sortTable: function(n, context) {
    var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
    table = document.getElementById(context.options.id);
    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.getElementsByClassName("row");
        /*Loop through all table rows (except the
        first, which contains table headers):*/
        for (i = 0; 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].getElementsByClassName("cell")[n];
            y = rows[i + 1].getElementsByClassName("cell")[n];
            /*check if the two rows should switch place,
            based on the direction, asc or desc:*/
            x = Number(x.innerHTML.toLowerCase()) ? Number(x.innerHTML.toLowerCase()) : x.innerHTML.toLowerCase();
            y = Number(y.innerHTML.toLowerCase()) ? Number(y.innerHTML.toLowerCase()) : y.innerHTML.toLowerCase();

            if (dir == "asc") {
                if (x > y) {
                    //if so, mark as a switch and break the loop:
                    shouldSwitch= true;
                    break;
                }
            } else if (dir == "desc") {
                if (x < y) {
                    //if so, mark as a switch and break the loop:
                    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;
            }
        }
    }

2 Comments

How would I do this?
The other two answers on this page managed to solve my problem. Thanks for the help though.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.