1

I am having some problems with two objects in my javascript code.

My first object is from an API call which I haven't listed here, but the data variable being passed into my getStudentStats() function is the result of that API call and its output can be seen in the image below highlighted [1]. It is a list of students and their associated data.

My second object is the result of a JSON call which can be seen below (the UWA.Data.getJson() function). Its output can be seen in the image below highlighted [2]. It is a list of students' IDs and some statistics from my local database, i.e. the number of flags they've received and the number of interventions that have been raised for them.

getStudentStats : function(data) {

    /* [1] Console log */
    console.log(data);

    var student_list = '';

    for( var i = 0; i < data.length; i++ )
        student_list += data[i].id + ',';

    student_list = student_list.substring(0, student_list.length - 1);

    var Students = [];
    var Student_Data = data;

    UWA.Data.getJson(FLAGS_Assign_Flags.url + 'get_students_stats&arg=' + student_list, function(data) {
        /* [2] Console log */
        console.log(data);

        for( var i = 0; i < data.length; i++ ) {
            var Student_ID = data[i].Student_ID;
            var obj = { 'flags': data[i].Flags, 'interventions': data[i].Interventions };
            Students[Student_ID] = obj;
        }

        /* [3] Console log */
        console.log(Students);

        FLAGS_Assign_Flags.displayStudents(Students, Student_Data);
    });

},

What I'm trying to do is, basically, display some information from both of these objects (using jQuery .html() and a string variable).

displayStudents : function(students, data) {

    /* Set up our HTML variable which we'll .html() when it's populated */
    var StudentsHTML = '<ul id="students_display">';

    for( var i = 0; i < data.length; i++ ) {
        /* For each student in the `data` object, grab their ID to access the correct element in the students object */
        var id = data[i].id;

        /* Set up a variable which we'll use to display the students' stats in our LI */
        var stats = '<div>';

        /* If the student doesn't have any flags or interventions, manually set the text */
        if( typeof students[id] != 'undefined' )
            stats += ' (F:<span class="f">' + students[id].Flags + '</span>|I:<span class="i">' + students[id].Flags + '</span>)';
        else
            stats += ' (F:<span class="f">0</span>|I:<span class="i">0</span>)'; 

        stats += '</div>';

        /* Produce checkbox, name and stats for each student and add them to the HTML variable */
        StudentsHTML += '<li><input type="checkbox" name="students" value="' + data[i].id + '" />&nbsp;' + data[i].firstname + ' ' + data[i].surname + stats + '</li>';
    }

    StudentsHTML += '</ul>';

    /* Set the HTML... */
    $('#students').html(StudentsHTML);

    /* Do some other stuff not relevant to this question! */
    FLAGS_Assign_Flags.displayForm();

},

The problem is, as you can see in the image below highlighted [3], my Students object appears as a load of garbage in console and I can't access any information from it.

Scope or object

Is this a scope issue, or am I setting up my array of objects incorrectly?

turbonerd
  • 1,234
  • 4
  • 27
  • 63
  • Can you verify that `var Student_ID = data[i].Student_ID;` is giving you the value that you expect? Let's pinpoint where the `undefined` is actually happening to help determine the root cause. – TLS Aug 23 '13 at 12:50
  • Sorry, yes, I knew I should've added that - it definitely is. If I add `console.log(Student_ID);` directly after the line you quoted my script correctly logs the students' IDs. – turbonerd Aug 23 '13 at 12:51
  • Looks like it is definitely how the array is defined. Take a look here at this [question about array declarations](http://stackoverflow.com/q/6047582/475820). It might help you get it figured out. – TLS Aug 23 '13 at 13:02

2 Answers2

2
Students[Student_ID] = obj;

Is probably the problem.

For example:

var arr = [];
arr[4] = {};
=>
[undefined × 4, Object]
walleboom
  • 31
  • 3
  • I don't follow fully I'm afraid. What would you suggest as a solution? – turbonerd Aug 23 '13 at 12:54
  • Students.push(obj); And add the id of the student to obj then if you want to retrive a student from the array by id, make a search function (or use underscore.js). – walleboom Aug 23 '13 at 13:00
2

You have created var Students = []; as an array, and are later using it as an associative array to assign values to it:

Students[Student_ID] = obj;

This will not work, you should create the Students var as an object:

var Students = {};

Javascript does not have a notion of 'associative arrays', and you should use basic objects for this purpose.

Later on, you can loop through these with for in, too safely use for in, combine it with a call to hasOwnProperty:

for (var i in Students) {
    if (!Students.hasOwnProperty(i)) continue; // skip inherited properties
    // i == StudentID
    // Students[i] == your student object
}
NDM
  • 6,731
  • 3
  • 39
  • 52
  • Ahh.. I think we're on the right lines here Nicky. When I change my code to use the Object type instead of an Array as per your suggestion, I can now actually `console.log` the `Students` object. *However*, I was trying to create an *Array of Objects* so that I could, in the second function, access my students' statistics using something like `students[123456].Flags` (or `students[id_variable].Flags` more likely). With your code I'm unsure as to whether I can do that? – turbonerd Aug 23 '13 at 12:58
  • Scrap that Nicky, you can! Thanks :) – turbonerd Aug 23 '13 at 13:03
  • yes, you can. Javascript objects can be accessed with array operators: `Students.123456 == Students['123456']` – NDM Aug 23 '13 at 13:03
  • Aye. After changing my code to reflect your solution it didn't work. Then I quickly realised that I was trying to access the object's keys using the wrong case (should've been `flags` not `Flags`). Whoops! Working now, have accepted. – turbonerd Aug 23 '13 at 13:05