Himanshu Shekhar
Himanshu Shekhar

Reputation: 1262

Add or Delete particular node in nested JSON Object using javascript

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": []
            }]
        }]
    }
]
}

Tree structure

Upvotes: 1

Views: 2896

Answers (2)

RonyHe
RonyHe

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

James
James

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

Related Questions