I would like to know what is the best way to update the member of the multilevel object collection in JavaScript
Here is the simplified version of my collection:
You can build a map of objects by id for direct access:
var map = {};
(function recurse(steps) {
for (var i=0; i<steps.length; i++) {
var step = steps[i];
map[ step.id ] = step;
if ("childSteps" in step)
recurse(step.childSteps);
}
})(this.Steps);
function updateObjectByID(id, string) {
map[id].text = string;
}
A comment on your code: You overcomplified a lot. When the condition if(obj.id == objId)
is met, you have your obj
reference already!!! Now there is absolutely no need to search for a path to it, build a string from that, and eval it. Just assign directly to its property!
function(steps, objId, value, whatParam, command) {
if (typeof whatParam == 'undefined')
whatParam = 'selected';
$.each(steps, function(index, obj){
if(obj.id == objId) {
// removed a lot of unecessary stuff
// not sure, looks like "value" was evaled sometimes as well
obj[whatParam] = value;
} // insert an "else" here if ids are unique
if (typeof obj.childSteps != 'undefined') {
this.setupObjectState(obj.childSteps, objId, value, whatParam, command);
}
});
}
You must recursively descend your tree structure searching for the object with the target "id" and replace its text. For example:
function updateObjectByID(obj, id, text) {
if (!obj) return;
if (obj.id === id) {
obj.text = text;
} else if ((typeof(obj)==='object') && (obj.constructor===Array)) {
for (var i=0; i<obj.length; i++) {
updateObjectByID(obj[i], id, text);
}
} else if (obj.childSteps) {
updateObjectByID(obj.childSteps, id, text);
}
}
updateObjectByID(this.Steps, 11, 'String to be set');
However, this solution can be optimized by tree pruning.
Since you call updateObjectById()
with an ID, the ID has to be unique. Why don´t you change your structure like this then:
this.Steps = [
{ id: 1, text: "test" },
{ id: 2, parent: 1, text: "test" },
{ id: 3, parent: 1, text: "test" },
{ id: 4, parent: 1, text: "test" },
{ id: 10, parent: 4, text: "test" },
{ id: 11, parent: 4, text: "test" },
{ id: 5, parent: 1, text: "test"},
{ id: 6, parent: 1, text: "test"},
{ id: 7, parent: 1, text: "test"},
{ id: 8, parent: 1, text: "test"},
{ id: 9, parent: 1, text: "test"}
]
This way you can easily update your entries like this:
function updateObjectByID(id, text) {
for(var i = 0; i < this.Steps.length; i++) {
if(this.Steps[i].id === id) {
this.Steps[i].text = text;
break;
}
}
}
With the extra attribute parent
you can still easily get all the children of an element like this:
function getChildrenByID(id) {
var array = [];
for(var i = 0; i < this.Steps.length; i++) {
if(this.Steps[i].parent === id) {
array.push(this.Steps[i]);
}
}
return array;
}
function updateObjectByID(id, text) {
(function setText(steps) {
for(var i = 0; i < steps.length; i++){
var step = steps[i];
if(step.id === id){
step.text = text;
}
if ("childSteps" in step){
setText(step.childSteps);
}
}
})(this.Steps);
}
Here is demo. http://jsfiddle.net/qDWX8/