Search code examples
javascriptjsonrecursionunderscore.jsjqxtreegrid

Nested JSON iterate, Maximum call stack size exceeded


I have implemented a recursive function to iterate through a nested JSON. The issue I am facing is that it throws the error

Maximum call stack exceeded

The function that I implemented is as follows,

function createTreeMap (treeCatalog){
  var _this = this;

  _.each(treeCatalog, function (ele, inx){
    if(typeof (ele) === "object"){
      createTreeMap(ele);
    }else{
      //I create another JSON structure with the value as its property and its value as 1.
      _this.treeMap[ele] = 1;

    }
  });

}

and the JSON I am iterating through looks something like this,

[{
    "EmployeeID": 2,
    "FirstName": "Andrew",
    "LastName": "Fuller",
    "Country": "USA",
    "Title": "Vice President, Sales",
    "HireDate": "1992-08-14 00:00:00",
    "BirthDate": "1952-02-19 00:00:00",
    "City": "Tacoma",
    "Address": "908 W. Capital Way",
    children: [{
        "EmployeeID": 8,
        "FirstName": "Laura",
        "LastName": "Callahan",
        "Country": "USA",
        "Title": "Inside Sales Coordinator",
        "HireDate": "1994-03-05 00:00:00",
        "BirthDate": "1958-01-09 00:00:00",
        "City": "Seattle",
        "Address": "4726 - 11th Ave. N.E."
    }, {
        "EmployeeID": 1,
        "FirstName": "Nancy",
        "LastName": "Davolio",
        "Country": "USA",
        "Title": "Sales Representative",
        "HireDate": "1992-05-01 00:00:00",
        "BirthDate": "1948-12-08 00:00:00",
        "City": "Seattle",
        "Address": "507 - 20th Ave. E.Apt. 2A"
    }, {
        "EmployeeID": 3,
        "FirstName": "Janet",
        "LastName": "Leverling",
        "Country": "USA",
        "Title": "Sales Representative",
        "HireDate": "1992-04-01 00:00:00",
        "BirthDate": "1963-08-30 00:00:00",
        "City": "Kirkland",
        "Address": "722 Moss Bay Blvd."
    }, {
        "EmployeeID": 4,
        "FirstName": "Margaret",
        "LastName": "Peacock",
        "Country": "USA",
        "Title": "Sales Representative",
        "HireDate": "1993-05-03 00:00:00",
        "BirthDate": "1937-09-19 00:00:00",
        "City": "Redmond",
        "Address": "4110 Old Redmond Rd."
    }, {
        "EmployeeID": 5,
        "FirstName": "Steven",
        "LastName": "Buchanan",
        "Country": "UK",
        "Title": "Sales Manager",
        "HireDate": "1993-10-17 00:00:00",
        "BirthDate": "1955-03-04 00:00:00",
        "City": "London",
        "Address": "14 Garrett Hill",
        "expanded": "true",
        children: [{
            "EmployeeID": 6,
            "FirstName": "Michael",
            "LastName": "Suyama",
            "Country": "UK",
            "Title": "Sales Representative",
            "HireDate": "1993-10-17 00:00:00",
            "BirthDate": "1963-07-02 00:00:00",
            "City": "London",
            "Address": "Coventry House Miner Rd."
        }, {
            "EmployeeID": 7,
            "FirstName": "Robert",
            "LastName": "King",
            "Country": "UK",
            "Title": "Sales Representative",
            "HireDate": "1994-01-02 00:00:00",
            "BirthDate": "1960-05-29 00:00:00",
            "City": "London",
            "Address": "Edgeham Hollow Winchester Way"
        },{
            "EmployeeID": 9,
            "FirstName": "Anne",
            "LastName": "Dodsworth",
            "Country": "UK",
            "Title": "Sales Representative",
            "HireDate": "1994-11-15 00:00:00",
            "BirthDate": "1966-01-27 00:00:00",
            "City": "London",
            "Address": "7 Houndstooth Rd."
        }]
    }]
}];

My suspicion is the similar child property names. But is there a proper way of fixing this as the similar child names is a requirement.

Thank you very much :)

UPDATE

this example simulates the issue I am having : http://jsfiddle.net/qaoapays/1/


Solution

  • After binding your source to jqxTreeGrid it a small change it structure: add parent property, and data property, where data - reference to self.
    As workaround, to avoid infinite recursion you need miss this property, something like

    function iterate (obj){
        _.each(obj, function(ele, inx){
            if(typeof (ele) === "object" && ele !== obj && inx !== 'parent'){
                iterate(ele);
            }else{
                console.log(ele);
            }
        });
    }
    

      var employees = 
          [{
          "EmployeeID": 2,
              "FirstName": "Andrew",
              "LastName": "Fuller",
              "Country": "USA",
              "Title": "Vice President, Sales",
              "HireDate": "1992-08-14 00:00:00",
              "BirthDate": "1952-02-19 00:00:00",
              "City": "Tacoma",
              "Address": "908 W. Capital Way",
         children: [{
              "EmployeeID": 8,
                  "FirstName": "Laura",
                  "LastName": "Callahan",
                  "Country": "USA",
                  "Title": "Inside Sales Coordinator",
                  "HireDate": "1994-03-05 00:00:00",
                  "BirthDate": "1958-01-09 00:00:00",
                  "City": "Seattle",
                  "Address": "4726 - 11th Ave. N.E."
          }, {
              "EmployeeID": 1,
                  "FirstName": "Nancy",
                  "LastName": "Davolio",
                  "Country": "USA",
                  "Title": "Sales Representative",
                  "HireDate": "1992-05-01 00:00:00",
                  "BirthDate": "1948-12-08 00:00:00",
                  "City": "Seattle",
                  "Address": "507 - 20th Ave. E.Apt. 2A"
          }, {
              "EmployeeID": 3,
                  "FirstName": "Janet",
                  "LastName": "Leverling",
                  "Country": "USA",
                  "Title": "Sales Representative",
                  "HireDate": "1992-04-01 00:00:00",
                  "BirthDate": "1963-08-30 00:00:00",
                  "City": "Kirkland",
                  "Address": "722 Moss Bay Blvd."
          }, {
              "EmployeeID": 4,
                  "FirstName": "Margaret",
                  "LastName": "Peacock",
                  "Country": "USA",
                  "Title": "Sales Representative",
                  "HireDate": "1993-05-03 00:00:00",
                  "BirthDate": "1937-09-19 00:00:00",
                  "City": "Redmond",
                  "Address": "4110 Old Redmond Rd."
          }, {
              "EmployeeID": 5,
                  "FirstName": "Steven",
                  "LastName": "Buchanan",
                  "Country": "UK",
                  "Title": "Sales Manager",
                  "HireDate": "1993-10-17 00:00:00",
                  "BirthDate": "1955-03-04 00:00:00",
                  "City": "London",
                  "Address": "14 Garrett Hill",
                  "expanded": "true",
              children: [{
                  "EmployeeID": 6,
                      "FirstName": "Michael",
                      "LastName": "Suyama",
                      "Country": "UK",
                      "Title": "Sales Representative",
                      "HireDate": "1993-10-17 00:00:00",
                      "BirthDate": "1963-07-02 00:00:00",
                      "City": "London",
                      "Address": "Coventry House Miner Rd."
              }, {
                  "EmployeeID": 7,
                      "FirstName": "Robert",
                      "LastName": "King",
                      "Country": "UK",
                      "Title": "Sales Representative",
                      "HireDate": "1994-01-02 00:00:00",
                      "BirthDate": "1960-05-29 00:00:00",
                      "City": "London",
                      "Address": "Edgeham Hollow Winchester Way"
              }, {
                  "EmployeeID": 9,
                      "FirstName": "Anne",
                      "LastName": "Dodsworth",
                      "Country": "UK",
                      "Title": "Sales Representative",
                      "HireDate": "1994-11-15 00:00:00",
                      "BirthDate": "1966-01-27 00:00:00",
                      "City": "London",
                      "Address": "7 Houndstooth Rd."
              }]
          }]
      }];
    
      //// prepare the data
      var source = {
          dataType: "json",
          dataFields: [{
              name: 'EmployeeID',
              type: 'number'
          }, {
              name: 'FirstName',
              type: 'string'
          }, {
              name: 'LastName',
              type: 'string'
          }, {
              name: 'Country',
              type: 'string'
          }, {
              name: 'City',
              type: 'string'
          }, {
              name: 'Address',
              type: 'string'
          }, {
              name: 'Title',
              type: 'string'
          }, {
              name: 'HireDate',
              type: 'date'
          }, {
              name: 'children',
              type: 'array'
          }, {
              name: 'expanded',
              type: 'bool'
          }, {
              name: 'BirthDate',
              type: 'date'
          }],
          hierarchy: {
              root: 'children'
          },
          id: 'EmployeeID',
          localData: employees
      };
      var dataAdapter = new $.jqx.dataAdapter(source);
    
      // create Tree Grid
      $("#treeGrid").jqxTreeGrid({
          width: 680,
          source: dataAdapter,
          editable: true,
          filterable: true,
          theme: 'energyblue',
          columns: [{
              text: 'FirstName',
              dataField: 'FirstName',
              width: 150
          }, {
              text: 'LastName',
              dataField: 'LastName',
              width: 120
          }, {
              text: 'Title',
              dataField: 'Title',
              width: 200
          }, {
              text: 'Birth Date',
              dataField: 'BirthDate',
              cellsFormat: 'd',
              width: 120
          }, {
              text: 'Hire Date',
              dataField: 'HireDate',
              cellsFormat: 'd',
              width: 120
          }, {
              text: 'Address',
              dataField: 'Address',
              width: 250
          }, {
              text: 'City',
              dataField: 'City',
              width: 120
          }, {
              text: 'Country',
              dataField: 'Country',
              width: 120
          }]
    
      });
      $("#jqxbutton").jqxButton({
          theme: 'energyblue',
          height: 30
      });
      $('#jqxbutton').click(function () {
          $("#treeGrid").jqxTreeGrid('expandRow',2);
          iterate(employees);
          });
    
      function iterate (obj){
        _.each(obj, function(ele, inx){
              if(typeof (ele) === "object" && ele !== obj && inx !== 'parent'){
                  iterate(ele);
              }else{
                  console.log(ele);
              }
          });
      }
    <script src="http://documentcloud.github.io/underscore/underscore.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <link href="http://jqwidgets.com/public/jqwidgets/styles/jqx.energyblue.css" rel="stylesheet"/>
    <link href="http://jqwidgets.com/public/jqwidgets/styles/jqx.base.css" rel="stylesheet"/>
    <script src="http://jqwidgets.com/public/jqwidgets/jqx-all.js"></script>
    <div id="treeGrid"></div>
    <input type="button" style="margin: 20px;" id="jqxbutton" value="Expand a row" />

    Yet another way: pass to source - deep cloned object