1

I'm using the following code/data to display a list of our top-earning students in each House.


The data

User_Info is an array of Objects Attachment 1: User_Info is an array of Objects

User_Info is an array of Objects such as this Attachment 2: User_Info is an array of Objects such as this

Database_Info is an Object like this Attachment 3: Database_Info is an Object like this


The code

    HPAnalysisObject.dispHPTotals = function(User_Info, Database_Info) {
        // See attachments 1 and 2
        console.log(User_Info);
        // See attachment 3
        console.log(Database_Info);

        // "label" is just a text title, like "Eagles"
        var html = '<h2>' + HPAnalysisObject.label + '</h2>' + 
            // "TotalPoints" is an integer figure
            '<div id="total">' + Database_Info.TotalPoints + '</div>';

        // create the table to display
        html += '<table><tr><th class="name">Name</th><th class="points">Points</th></tr>';

        // use "for, in" to access the value of the object key (which is the user's ID)
        for (var id in Database_Info.UserDetails) {
            html += '<tr>';
            for (var i = 0; i < User_Info.length; i++) {
                if (User_Info[i].id == id) {
                    // if the User_Info and Database_Info objects match up on the User's ID, add table cells to our html variable
                    html += '<td class="name">' + User_Info[i].firstname + ' ' + User_Info[i].surname + '</td><td class="points">' + Database_Info.UserDetails[id] + '</td>';
                }
            }
            html += '</tr>';
        }

        html += '</table>';

        $('div#display').html(html);
    };

The problem

Oddly, in Firefox, these students display in the correct numerical order, as the students are received from my PHP script.

However, in Google Chrome and Internet Explorer, they appear in a seemingly-random order!

My first thought was to order the object, but having read a few questions on here, it seems like ordering objects isn't the best practice.

Can I rewrite this code so that I display the same tabular data - just in the right order on every browser?

Thanks in advance,

turbonerd
  • 1,234
  • 4
  • 27
  • 63
  • possible duplicate of [Does JavaScript Guarantee Object Property Order?](http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) – Oleg V. Volkov Sep 11 '12 at 16:06

4 Answers4

1

In most languages, you cannot assume that object attributes occur in any particular order.

One solution might be to add an accessor to each entry in UserDetails such as:

UserDetails={ ID:{ accessor:1, id: ID } }

And then sort the records on UserDetails[ID].accessor.

Another might be to construct UserDetails as an array of elements which encode key values as "key:value", splitting each retrieved elements on /:/ as in:

[ "90030:87" ... ]

EDIT

Assuming

var userDetails={
                  a:{i:3,key:'third'},
                  b:{i:1,key:'first'},
                  c:{i:2,key:'second'}
};

where i is the accessor, you can create a sorted array of objects using

var sortedObjs=Object.keys(userDetails)
                     .map(function(k){ return userDetails[k] })
                     .sort(function(left,right){ return left['i']-right['i'] });

which extracts keys from userDetails, creates an array of the keyed elements via map and sorts the resulting elements by their accessor value such that

console.log(sortedObjs.map(function(elt){return elt.key}).join(','))

will print to the console:

first,second,third
Rob Raisch
  • 17,040
  • 4
  • 48
  • 58
  • The accessor sounds like the best approach. How would I go about sorting the records from that key though? Would it be a simple `for` loop? I can't get my head round how it would work. – turbonerd Sep 12 '12 at 08:45
0

Objects are an unsorted mapping of keys to values, their order is never guaranteed.

When I get anything like this, I like to build an array using the ID as numeric keys. For instance, something like this in PHP:

$out = Array();
while($row = database_get_row($set)) { // replace with your choice of database library
    $out[$row['id']] = $row;
}
ksort($out);
$out = array_values($out);

In this way, you can ensure that the array is in order of increasing ID, and then pass that array to JavaScript for use in a for(i=0;i<l;i++) loop.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Thanks for that Kolink. The `Database_Info` object is built from a PHP Script in which I utilise `arsort` to make sure the array is ordered correctly. However, the problem appears to lie with the `for in` loop in JavaScript; so ideally I'm looking to replace that. – turbonerd Sep 11 '12 at 15:38
0

You'll have to sort Database_Info.UserDetails using an array wrapper:

// test data using same data as example but with no order
var Database_Info = { 
  UserDetails : { 
    137473 : 87, 
    90132 : 126, 
    90057 : 79, 
    90030 : 87, 
    90095 : 82 
  }
}

var objWrapper = [];
for (key in Database_Info.UserDetails) {
  objWrapper.push(key);
}
objWrapper.sort(); // default sort = numeric order ascending

for (a = 0, b = objWrapper.length; a < b; a++) {
  var userInfo = Database_Info.UserDetails[objWrapper[a]];
  // do something interesting
  console.log(userInfo);
}
Matt Brock
  • 5,337
  • 1
  • 27
  • 26
0

I decided to wrap my Objects in a sortable array. This appeared to do the trick.

HPAnalysisObject.dispHPTotals = function(User_Info, Database_Info) {            
    // make a sortable array
    var Combined_Info = [];

    // "label" is just a text title, like "Eagles"
    var html = '<h2>' + HPAnalysisObject.label + '</h2>' + 
        // "TotalPoints" is an integer figure
        '<div id="total">' + Database_Info.TotalPoints + '</div>';

    // create the table to display
    html += '<table><tr><th class="name">Name</th><th class="points">Points</th></tr>';

    // use "for, in" to access the value of the object key (which is the user's ID)
    for (var id in Database_Info.UserDetails) {

        for (var i = 0; i < User_Info.length; i++) {
            if (User_Info[i].id == id) {
                var StudentInfo = { name: User_Info[i].firstname + ' ' + User_Info[i].surname, points: Database_Info.UserDetails[id] };
                Combined_Info.push(StudentInfo);
            }
        }

    }

    Combined_Info.sort( function(a, b) {
        return b.points - a.points;
    });

    for (var i = 0; i < Combined_Info.length; i++) {
        html += '<tr>';
        html += '<td class="name">' + Combined_Info[i].name + '</td><td class="points">' + Combined_Info[i].points + '</td>';
        html += '</tr>';
    }

    html += '</table>';

    $('div#display').html(html);
};
turbonerd
  • 1,234
  • 4
  • 27
  • 63