Search code examples
javascriptjquerytablesorter

tablesorter not sorting updated rows correctly


I'm working on a personal project, and I am having trouble getting my 5th column to sort properly in Chrome using tablesorter. I made a jsfiddle for this and it works fine in it.

Can someone maybe point me in the right direction to fix this and explain why the jsfiddle works, but chrome alone doesn't?

Here's the jsfiddle: https://jsfiddle.net/3rbp6okz/

Here is the full file:

<html>
<head>

<title>Dark Insanity Guild Roster</title>
<script type="text/javascript" src="jq/tablesorter-master/jquery-3.1.0.js"></script> 
<script type="text/javascript" src="jq/tablesorter-master/jquery.tablesorter.js"></script> 
    <script>
    var playernamelink = [];
    var playername = [];
    var playerclass =[];
    var playerspec =[];
    var playerlvl =[];
    var playerilvl =[];
    var playerrealm =[];
    var totalPlayers = 0;
    //start data pull
    pull();
    //get the data from battle.net
    function pull()
    {   
        $.ajax
        (
            {
                url: 'https://us.api.battle.net/wow/guild/Sen\'jin/dark%20insanity?fields=members&locale=en_US&jsonp=guilddata&apikey=tfawppjfe9aj9zd5pudqv76x86fhbnpe',
                type:"GET",
                data: { fields: "members" },
                dataType: "jsonp",
                contentType:"application/json",
                jsonpCallback:"guilddata",
                success: function(data)
                {
                    for(var i in data.members)
                    {
                        playernamelink[i] = '<a href="http://us.battle.net/wow/en/character/' +fixRealm(data.members[i].character.realm)+ '/' + data.members[i].character.name + '/simple" target=_blank>'+ data.members[i].character.name + '</a>';
                        playername[i] = data.members[i].character.name;
                        playerclass[i] = getClass(data.members[i].character.class);
                        playerspec[i] = (data.members[i].character.spec ? data.members[i].character.spec.name : "");
                        playerlvl[i] = data.members[i].character.level;
                        playerrealm[i] = fixRealm(data.members[i].character.realm);
                        totalPlayers++;
                    };
                },
                complete: function(data)
                {
                    for(var i = 0; i < totalPlayers; i++)
                    {
                    //only make API call if player level is 110
                        if(playerlvl[i] == '110')
                        {
                            getIlvl(playerrealm[i], playername[i], i);
                        }   
                    }
                    populateTable();
                }
            }
        );
    }
    //call the api to get players Ilvl
    function getIlvl(realm,player,index)
    {
        var ilvl;
        $.ajax
        (
            {
                //https://us.api.battle.net/wow/character/sen'jin/Palador?fields=items&locale=en_US&apikey=tfawppjfe9aj9zd5pudqv76x86fhbnpe
                url: 'https://us.api.battle.net/wow/character/'+realm+'/'+player+'?fields=items&locale=en_US&json=player&apikey=tfawppjfe9aj9zd5pudqv76x86fhbnpe',
                type:"GET",
                data2: {fields: "items"},
                dataType: "json",
                contentType:"application/json",
                jsonpCallback:"player",
                success: function(data2)
                {
                    //console.log(data2);
                    //console.log(data2.items.averageItemLevel);
                    ilvl = data2.items.averageItemLevel;
                },
                complete: function(data)
                {
                    playerilvl[index] = ilvl;
                    //UPDATE cell with Ilvl
                    var x = document.getElementById("players").rows[index].cells;
                    x[4].innerHTML = playerilvl[index];
                }
            }
        );
    }
    //format realm string for URL
    function fixRealm(realm)
    {
        return (realm == 'Sen\'jin') ? 'Sen\'jin' : 'Quel\'dorei';
    }
    //return class string
    function getClass(classNumber)
        {
            switch(classNumber)
            {
                case(1):
                    return 'Warrior';
                break;
                case(2):
                    return 'Paladin';
                break;
                case(3):
                    return 'Hunter';
                break;
                case(4):
                    return 'Rogue';
                break;
                case(5):
                    return 'Priest';
                break;
                case(6):
                    return 'Death Knight';
                break;
                case(7):
                    return 'Shaman';
                break;
                case(8):
                    return 'Mage';
                break;
                case(9):
                    return 'Warlock';
                break;
                case(10):
                    return 'Monk';
                break;
                case(11):
                    return 'Druid';
                break;
                case(12):
                    return 'Demon Hunter';
                break;
            }
        }
    //populate table with data after completed API call to guild data
    function populateTable()
    {

        var tableRef = document.getElementById('players').getElementsByTagName('tbody')[0];
        for(var i = 1; i < totalPlayers; i++)
        {
            var row = tableRef.insertRow();
            var cell1 = row.insertCell(0);
            var cell2 = row.insertCell(1);
            var cell3 = row.insertCell(2);
            var cell4 = row.insertCell(3);
            var cell5 = row.insertCell(4);
            cell1.innerHTML = playernamelink[i];
            cell2.innerHTML = playerclass[i];
            cell3.innerHTML = playerspec[i];
            cell4.innerHTML = playerlvl[i];
            cell5.innerHTML = '0';
        }
        //initialize tablesorter
        $("#players").tablesorter({
            headers: {
                4: {
                     sorter: "digit"
                }
            }
       });
    }
    </script>

    </head>
    <!--<link rel="stylesheet" type="text/css" href="C:\Users\Ambassador RickFace\Desktop\web\jq\tablesorter-master\themes\blue\style.css">
    -->
    <body>
    <h1>Dark Insanity Guild Members</h1><br>
    <table id="players" class="tablesorter">
    <thead> 
        <tr>
            <th>Name</th>
            <th>Class</th>
            <th>Specialization</th>
            <th>Level</th>
            <th>Item Level</th>
        </tr>
    </thead>
    <tbody id="tbody">
    </tbody>  
    </table>

    </body>

    </html>

Solution

  • Your code works in JSFiddle, but not on your page because the javascript is run before the <body> has completed loading. Either move all your javascript to the bottom of the page, above the </body> tag, or wrap the javascript in a document ready function:

    $(function() {
        // add all your javascript here
    });
    

    Edit: Oh and the parser name is "digit" not "integer":

    { 4: {sorter:"digit"} }
    

    Edit2: Your fiddle is loading tablesorter twice and initializing it a bunch of times inside the for loop - here is an updated demo and the fixed loops code:

    function populateTable() {
    
      var tableRef = document.getElementById('players').getElementsByTagName('tbody')[0];
      for (var i = 1; i < totalPlayers; i++) {
        var row = tableRef.insertRow();
        var cell1 = row.insertCell(0);
        var cell2 = row.insertCell(1);
        var cell3 = row.insertCell(2);
        var cell4 = row.insertCell(3);
        var cell5 = row.insertCell(4);
        cell1.innerHTML = playernamelink[i];
        cell2.innerHTML = playerclass[i];
        cell3.innerHTML = playerspec[i];
        cell4.innerHTML = playerlvl[i];
        cell5.innerHTML = '0';
      }
      //initialize tablesorter
      $("#players").tablesorter({
        headers: {
          4: {
            sorter: "digit"
          }
        }
      });
    }
    

    Update 2: Oh, I missed the fact that more asynchronous data was being loaded within the ajax complete callback. I think the easiest solution would be to set up some promises and then in the done function, update tablesorter (updated demo):

    var items = [];
    function getIlvl(realm, player, index) {
      var ilvl;
      items.push($.ajax({...}));
      // ...
    }
    
    function populateTable() {
      // ...
      $.when.apply($, items).done(function() {
        $('#players').trigger('update');
      });
    }