Search code examples
javascriptjqueryloopsobjectnested-loops

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".


Solution

  • 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