I am trying to assign an element within a json object with some new value (text/object/array). I have a swap function which takes in the json object, an array with the indexes to retreive the element and the value to replace it with. Currently I am using eval, which accoridng to some is "evil". Is there a better way to do this without eval or is eval ok in this case? Keep in mind it must be dynamic because the array may change. Also it may be important to note that I am programatically creating the array parameter.
//array looks like: ["cluster", "2", "segment", "0", "node", "3"]
JsonManager.prototype.swap = function(json, array, val){
var statement = "json";
for (var i = 0; i < array.length; i++) {
if(!isNumeric(array[i]))
{
statement += "[\"" + array[i] + "\"]";
}else{
statement += "[" + array[i] + "]"
}
}
statement += " = val";
eval(statement);
};
Example JSON Object:
var customers = {
"cluster": [{
"clusterid": "cluster1.1",
"color": "blue",
"flights": "784",
"profit": "524125",
"clv": "2364",
"segment": [{
"segmentid": "segment1.1",
"color": "green",
"flights": "82",
"profit": "22150",
"clv": "1564",
"node": [{
"nodeid": "node1.1",
"color": "orange",
"xpos": "1",
"ypos": "1"
}, {
"nodeid": "node1.2",
"color": "blue",
"xpos": "1",
"ypos": "2"
}, {
"nodeid": "node1.3",
"color": "orange",
"xpos": "1",
"ypos": "3"
}, {
"nodeid": "node1.4",
"color": "orange",
"xpos": "1",
"ypos": "4"
}]
}, {
"segmentid": "segment1.2",
"color": "red",
"flights": "2",
"profit": "2150",
"clv": "1564",
"node": [{
"nodeid": "node2.1",
"color": "tan",
"xpos": "2",
"ypos": "1"
}, {
"nodeid": "node2.2",
"color": "tan",
"xpos": "2",
"ypos": "2"
}, {
"nodeid": "node2.3",
"color": "tan",
"xpos": "2",
"ypos": "3"
}, {
"nodeid": "node2.4",
"color": "tan",
"xpos": "2",
"ypos": "4"
}]
}]
}, {
"clusterid": "cluster1.2",
"flights": "4",
"profit": "5245",
"clv": "2364",
"segment": [{
"segmentid": "segment1.2",
"flights": "2",
"profit": "2150",
"clv": "1564",
"node": [{
"nodeid": "node3.1",
"xpos": "3",
"ypos": "1"
}, {
"nodeid": "node3.2",
"xpos": "3",
"ypos": "2"
}, {
"nodeid": "node3.3",
"xpos": "3",
"ypos": "3"
}, {
"nodeid": "node3.4",
"xpos": "3",
"ypos": "4"
}]
}]
}, {
"clusterid": "cluster1.3",
"flights": "10",
"profit": "456978",
"clv": "548",
"segment": [{
"segmentid": "segment1.3",
"flights": "2",
"profit": "2150",
"clv": "1564",
"node": [{
"nodeid": "node4.1",
"xpos": "4",
"ypos": "1"
}, {
"nodeid": "node4.2",
"xpos": "4",
"ypos": "2"
}, {
"nodeid": "node4.3",
"xpos": "4",
"ypos": "3"
}, {
"nodeid": "node4.4",
"xpos": "4",
"ypos": "7"
}]
}]
}]
};
Here is my test method:
JsonManager.prototype.init = function(){
var clause = new Clause("nodeid", "node4.4");
var indexes = this.search(customers, clause);
this.swap(customers, indexes.reverse(), {"name": "kevin"});
var test = customers["cluster"][2]["segment"][0]["node"][3]; //hard coded pointer to node4.4
var breakPoint = "breakpoint"; //Just used as a point to stop the debugger to see test
};
For future reference here is the solution further commented:
JsonManager.prototype.swap = function(obj, path, value) {
//This is the inner function we are recursing into
function descend(obj, path) {
/*This if statement is used to stop the recrusion,
when we have iterated through all the paths, it returns
the object above our desired object */
if (path.length == 0) {
return obj;
}
/*Recurse into the function passing in the top level object and remove
the top level object from our path*/
return descend(obj[path[0]], path.slice(1));
}
//Pass in the object and the (path - the last element)
var node = descend(obj, path.slice(0, -1));
//Get the last node in path, pull it from node and assign the value
node[path[path.length - 1]] = value;
};