Reputation: 1262
I want to make tree like structure. In each node has two sign (+ to add one more node and - to delete the particular node). Problem which I'm facing is how to add/ delete node(children) from nested json. For one or two level nesting its fine, but for more than one, I'm not able to make some general code to do this operation. Below is the default json and picture of tree on which I have to do add/delete operation. In HTML and CSS I have no problem.Some lead or hint is welcomed as for last 2 days I'm working on this. Thanks
JSON :
{
"name": "abc",
"children": [{
"name": "def",
"children": [{
"name": "jkl",
"children": [{
"name": "vwxyz",
"children": []
}]
}]
},
{
"level": "2",
"name": "ghi",
"children": [{
"name": "mno",
"children": []
}, {
"name": "pqr",
"children": [{
"name": "stu",
"children": []
}]
}]
}
]
}
Upvotes: 1
Views: 2896
Reputation: 942
One approach would be to use a Node data structure instead of JSON. Plain JS objects can be translated to and from JSON easily when needed.
This way, handling the data is much simpler. You can hook up DOM events to methods on nodes and translate to JSON when you're done
function Node(value, parent) {
let children = [];
let self = {
value: value,
children: children,
// create and return a new node for the value
add: value => {
let child = Node(value, self);
children.push(child);
return child;
},
// remove this node from its parent, if it has one
remove: () => {
if (parent !== null && typeof parent !== 'undefined') {
let indexInParent = parent.children.indexOf(self);
if (indexInParent > -1) {
parent.children.splice(indexInParent, 1);
}
}
},
// return a plain object that has only data and contains no references to parents
// JSON.stringify cannot handle circular references
dataOnly: function () {
return {
value: value,
children: children.map(c => c.dataOnly())
}
},
// return a JSON string for this object
makeJSON: () => JSON.stringify(self.dataOnly())
};
return self;
}
root = Node('lame');
child = root.add('child');
console.log(root.makeJSON());
// logs {"value":"lame","children":[{"value":"child","children":[]}]}
Upvotes: 1
Reputation: 22227
Since you have unique names you can make a lookup object with the name attribute as the key and the tree node as its value. Then you can step to any node quickly given its name. By adding a parent property to each node object you can find a given node’s parent.
var data = { name: "abc", ... };
var lookup = {};
function buildLookup(node, parent) {
node.parent = parent;
lookup[node.name] = node;
if (node.children) {
for (var i = 0; i < node.children.length; i++) {
buildLookup(node.children[i], node);
}
}
}
buildLookup(data, null);
// lookup object now populated
Your -/+ buttons can incorporate the name attribute for passing to event handler:
<button class="button-plus" data-name="def">+</button>
<button class="button-minus" data-name="def">-</button>
And the handler:
var addBtns = document.querySelectorAll(".button-plus");
for (var i=0; i < addBtns.length; i++) {
addBtns[i].addEventListener("click", function (e) {
var node = lookup[this.dataset.name];
// create a new empty child
var child = {
name: "new child",
parent: node,
children: []
};
// add it to the children array
node.children.push(child);
// add it to the lookup
lookup[child.name] = child;
});
}
Upvotes: 1