imoses imoses - 3 months ago 7
Javascript Question

Loop through object with nested $.each

I'm having trouble looping through an object using a nested $.each. The object is a series of object of the same type/class nested under rootObject.

The object

var rootObject ={};

rootObject.reportObject1.name = "reportObject1 Name";
rootObject.reportObject1.prop1 = "reportObject1 Prop1_Value";
rootObject.reportObject1.prop2 = "reportObject1 Prop2_Value";

rootObject.reportObject1.reportObjectA.name = "reportObjectA Name";
rootObject.reportObject1.reportObjectA.prop1 = "reportObjectA Prop1_Value";
rootObject.reportObject1.reportObjectA.prop2 = "reportObjectA Prop2_Value";


The Loop

$.each(rootObject, function(index0, value0){
console.log(value0.name);

$.each(value0, function(index1, value1){
console.log(value1.name);
}

}


The Problem


  1. value1.name
    is returning object properties other than name in the loop. It's seemingly attempting to return value.name for
    prop1
    &
    prop2
    , resulting in "undefined" values.

  2. When looking into the value of
    value0
    during debugging,
    value0
    appears to loose its value as it enters the nested loop. I.e at
    console.log(value1.name)
    ,
    value0
    , from the parent loop, becomes
    undefined
    ;

  3. When looking into the child loop (
    index1, value1
    ) during debugging, I see that
    value1
    now equals
    value0.name
    , and
    index1
    equals "name".


Answer

You can automatically define properties one level deep, but for two you need to stop and instantiate the parent:

var rootObject ={};

rootObject.reportObject1 = {}; // HERE
rootObject.reportObject1.name = "reportObject1 Name";
rootObject.reportObject1.prop1 = "reportObject1 Prop1_Value";
rootObject.reportObject1.prop2 = "reportObject1 Prop2_Value";

rootObject.reportObject1.reportObjectA = {}; // and HERE
rootObject.reportObject1.reportObjectA.name = "reportObjectA Name";
rootObject.reportObject1.reportObjectA.prop1 = "reportObjectA Prop1_Value";
rootObject.reportObject1.reportObjectA.prop2 = "reportObjectA Prop2_Value";

Without that, none of these properties are actually getting defined, leading to your undefined results.

The next issue is another syntax problem: you're missing closing parentheses on the two $.each() calls:

$.each(rootObject, function(index0, value0){
  console.log(value0.name);

  $.each(value0, function(index1, value1){
    console.log(value1.name);
  }); // HERE

}); // and HERE

With these two fixes, your console output shows:

reportObject1 Name
undefined (x3)
reportObjectA Name

To get the correct output, or at least some sample output, you could use this little gem (from here). Because your structure could potentially have more than two levels, recursion seems appropriate here.

function enumerate(o,s){

    //if s isn't defined, set it to an empty string
    s = typeof s !== 'undefined' ? s : "";

    //iterate across o, passing keys as k and values as v
    $.each(o, function(k,v){

        //if v has nested depth
        if(typeof v == "object"){

            //write the key to the console
            console.log(s+k+": ");

            //recursively call enumerate on the nested properties
            enumerate(v,s+"  ");

        } else {

            //log the key & value
            console.log(s+k+": "+String(v));
        }
    });
}

If you try enumerate(rootObject), you will get:

reportObject1: 
   name: reportObject1 Name
   prop1: reportObject1 Prop1_Value
   prop2: reportObject1 Prop2_Value
   reportObjectA: 
     name: reportObjectA Name
     prop1: reportObjectA Prop1_Value
     prop2: reportObjectA Prop2_Value