2

What I have is a JSON tree of the following structure:

{
    "projects": {
        "Proj1": {
            "milestones": {
                "default": "20150101",
                "default2": "20140406",
                "default3": "20140101",
                "default4": "20131231",
                "default5": "20131220"
            }
        },
        "Proj2": {
            "milestones": {
                "default": "20131231",
                "default2": "20131220"
            }
        }
    }
}

I have code to read it into a web page, with the 'default' part in text, and the numbers/dates in a text box/form. The idea is that you can change the dates and submit, which goes to the backend and gets written to a file. All that works for the most part. What I can figure out is how to iterate through the JSON tree I have and write the new values. For example:

Accessing JSONTREE.projects.Proj1.milestones.default returns the value for that key. Setting the value with that call changes the value appropriately. What I want to do is iterate through the entire tree and set the values of the 'defaults' based on whatever is in the form box. I have this:

$.each(formJSON.projects, function (projectName) {
        $.each(this, function (selection) {
            $.each(this, function (milestones, date) {
                var saltKey = projectName + "-" + milestones;
                date = document.getElementById(saltKey).value;
           });
       });
});

but it does nothing, even though 'alert(date)' returns a value. I suspect this is because it's the value, and not a reference to the object, but how can I get to the object? I suspect it's simple, but I'm not a pro with jQuery/JS.

TL;DR How do I get references to a key in a nested JSON tree so I can change the value?

EDIT: Okay, I think this is what I needed: JS/Jquery - using variable in json selector. I changed the 'date' portion to: formJSON.projects[projectName][selection][milestones] = document.getElementById(saltKey).value; which seems to work.

Community
  • 1
  • 1
Randall Sewell
  • 43
  • 1
  • 10
  • This is actually not jquery, but if you are familiar with angularjs, check out [json-tree](http://krispo.github.io/json-tree/) directive. – krispo Jun 18 '14 at 20:59

2 Answers2

2

I ran into the same problem and this is my solution to iterate over a JSON object (MongoDB) and modify certain elements regardless of whether these are properties of the object or property is an array with more objects. I know the question is old, but it can be useful to someone. Assuming we have an object like this or even more complex.

var mixData = {
  "Hello": "World",
  "Foo" : "Bar",
  "sudo": [
    { "apt-get": "upgrade" , "force": false },
    { "apt-get": "update" , "force": true}
  ],
  "colors": ["blue","green"],
  "numbers":{
    "integer": [
      {"num": 1},
      {"num": 2},
      {"num": 3}
    ],
    "operator": "addition"
  } 
};

And we want to replace some string (blue in this case), but we don't know where is or what kind of constructor has our data.

// Detect if the element is an Array
function isElementArray(element){
  return (element.constructor === Array ? true : false);
}
//Detect if the element is an Object
function isElementObject(element){
  return (element.constructor === Object ? true : false);
}

Now that we have these two functions, we use a third to iterate over the item, regardless of whether an object or array.

function iterate(element){
  //Check if the element is an Object
  if(isElementObject(element)){
    for (var property in element){
      if(isElementObject(element[property])){
        element[property] = iterate(element[property]);
      }else if(isElementArray(element[property])){
        //An array
        for(var x = 0; x < element[property].length; x++){
          element[property][x] = iterate(element[property][x]);
        }
      }else{
        if(element.hasOwnProperty(property)){
          console.log("New object inside object property");
          element[property] = iterate(element[property]);
        }else{
          element[property] = replaceElement(element[property].toString());
          console.log("Single Element: " + element[property] )
          console.log(element + " " + element[property]);
        }
      }
    }
  }else if(isElementArray(element)){
    //An Array
    for (var x = 0; x < element.length; x++){
      element[x] = iterate(element[x]);
    }
  }else{
    //Single element in array or property
    element = replaceElement(element.toString());
    console.log("Single Element : " + element);
  }
  return element;
}

And the function we need to use to replace our string.

function replaceElement(element){
  if(element === "blue"){
    return "Blue is the warmest color"
  }else{
    return element;
  }
}

And finally, we can get the result:

console.log(iterate(mixData));

The result is:

{
    "Hello": "World",
    "Foo" : "Bar",
    "sudo": [
      { "apt-get": "upgrade" , "force": false },
      { "apt-get": "update" , "force": true}
    ],
    "colors": ["Blue is the warmest color","green"],
    "numbers":{
      "integer": [
        {"num": 1},
        {"num": 2},
        {"num": 3}
      ],
      "operator": "addition"
    } 
};

You can change the replace function to suit your needs. And of course, remove al the console logs.

manuerumx
  • 1,230
  • 14
  • 28
1

Your editing the passed value and not the original JSON object.

One way to fix this is to create a new JSON object, build as you iterate through the existing one, and then overwrite the original or use the new JSON object.

Another is to create a var holding the original JSON object and either pass it through your functions or access it directly inside the functions.

bob0the0mighty
  • 782
  • 11
  • 28
  • That's what I figured the problem was ($.each returns a value and not a reference), but I don't really know how to build a new JSON object. I know generally to create the new object, but how do you add nested levels? The problem I had with trying something like that earlier was using variables in JSON references: var someNewThing = foo. 'JSONtree.someNewThing.default' then doesn't return the value for 'JSONtree.foo.default' – Randall Sewell Jun 16 '14 at 19:21
  • https://stackoverflow.com/questions/10919965/how-do-i-encode-a-javascript-object-as-json Since JSON objects are essentially arrays, you can build them by like building string indexed arrays. I recommend looking at the Wikipedia page for JSON too. https://en.wikipedia.org/wiki/JSON – bob0the0mighty Jun 16 '14 at 19:29
  • Hmm, so I understand that part, but how do I pass a variable as part of a JSON reference (myJSON.projects..milestones.)? – Randall Sewell Jun 16 '14 at 19:41
  • Okay, I think this is what I needed: http://stackoverflow.com/questions/15432627/js-jquery-using-variable-in-json-selector. I changed the 'date' portion to: formJSON.projects[projectName][selection][milestones] = document.getElementById(saltKey).value; which seems to work. Thank you! – Randall Sewell Jun 16 '14 at 19:52