1

I have an array of json like this:

var tree = [
      {
        text: "Parent 1",
        id: 1,
        nodes: [
          {
            text: "Child 1",
            id: 2,
            nodes: [
              {
                text: "Grandchild 1"
                id: 3,
              },
              {
                text: "Grandchild 2"
                id: 4,
                nodes: [
                  {
                    text: "Grandchild 3"
                    id: 10,
                  },
                  {
                    text: "Grandchild 4"
                    id: 11,
                    nodes: [
                      {
                        text: "Grandchild 5"
                        id: 12,
                      },
                      {
                        text: "Grandchild 6"
                        id: 13,
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            text: "Child 2"
            id: 5,
          }
        ]
      },
      {
        text: "Parent 2"
        id: 6,
      },
      {
        text: "Parent 3"
        id: 7,
      },
      {
        text: "Parent 4"
        id: 8,
      },
      {
        text: "Parent 5"
        id: 9,
      }
    ];

I'm trying to create a function that would take as parameter the tree, and id, and a newText parameter, that would find the node with the given id, replace the text by newText, and return the modified json.

Ex:

editTree(tree, 11, "Granchild 13435")

Is there a way to achieve this ? I don't know how to solve this since I need the path to the key in order to edit the tree.

Graham Slick
  • 6,692
  • 9
  • 51
  • 87

4 Answers4

2

You can use recursive function for this.

var tree = [{"text":"Parent 1","id":1,"nodes":[{"text":"Child 1","id":2,"nodes":[{"text":"Grandchild 1","id":3},{"text":"Grandchild 2","id":4,"nodes":[{"text":"Grandchild 3","id":10},{"text":"Grandchild 4","id":11,"nodes":[{"text":"Grandchild 5","id":12},{"text":"Grandchild 6","id":13}]}]}]},{"text":"Child 2","id":5}]},{"text":"Parent 2","id":6},{"text":"Parent 3","id":7},{"text":"Parent 4","id":8},{"text":"Parent 5","id":9}]

function editTree(tree, id, val) {
  for (var i in tree) {
    if (i == 'id') {
      if (tree[i] == id) {
        tree.text = val
        return 1;
      }
    }
    if (typeof tree[i] == 'object') editTree(tree[i], id, val)
  }
  return tree;
}


console.log(editTree(tree, 11, "Granchild 13435"))
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
2

You could use an iterative and recursive approach for searching the node. If found stop iteration and return.

This proposal uses Array#some, which allowes to exit the iteration.

If a node from an actual node exists and the node is an array, then this node gets iterated.

function editTree(tree, id, text) {
    tree.some(function iter(o) {
        if (o.id === id) {
            o.text = text;
            return true;
        }
        return Array.isArray(o.nodes) && o.nodes.some(iter);
    });
}

var tree = [{ text: "Parent 1", id: 1, nodes: [{ text: "Child 1", id: 2, nodes: [{ text: "Grandchild 1", id: 3, }, { text: "Grandchild 2", id: 4, nodes: [{ text: "Grandchild 3", id: 10, }, { text: "Grandchild 4", id: 11, nodes: [{ text: "Grandchild 5", id: 12, }, { text: "Grandchild 6", id: 13, }] }] }] }, { text: "Child 2", id: 5, }] }, { text: "Parent 2", id: 6, }, { text: "Parent 3", id: 7, }, { text: "Parent 4", id: 8, }, { text: "Parent 5", id: 9, }];

editTree(tree, 11, "Granchild 13435");    
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Here is a simple function to find a node matching a property and a value :

function findNode(nodes, prop, value) {
  if(!value || !(nodes instanceof Array)) return;
  for(var i=0; i<nodes.length; i++) {
      if(node = (value == nodes[i][prop]) ? nodes[i] : findNode(nodes[i]['nodes'], value)) {
        return node;
      }
  }
}

Then simply call :

// Find node with id = 10
var node = findNode(tree, 'id', 10);
if(node) {
  // Yeah! we found it, now change its text
  node['text'] = 'Changed!';
}

// Ensure tree has been updated
console.log(tree);

Sample snippet (check out that text of node with id = 10 has changed) :

var tree=[{text:"Parent 1",id:1,nodes:[{text:"Child 1",id:2,nodes:[{text:"Grandchild 1",id:3},{text:"Grandchild 2",id:4,nodes:[{text:"Grandchild 3",id:10},{text:"Grandchild 4",id:11,nodes:[{text:"Grandchild 5",id:12},{text:"Grandchild 6",id:13}]}]}]},{text:"Child 2",id:5}]},{text:"Parent 2",id:6},{text:"Parent 3",id:7},{text:"Parent 4",id:8},{text:"Parent 5",id:9}];


function findNode(nodes, prop, value) {
  if(!value || !(nodes instanceof Array)) return;
  for(var i=0; i<nodes.length; i++) {
      var node = (value == nodes[i][prop]) ? nodes[i] : findNode(nodes[i]['nodes'], prop, value);
      if(node ) {
        return node;
      }
  }
}

var node = findNode(tree, 'id', 10);
if(node) {
  node['text'] = 'Changed!';
}

console.log(tree)
Stephane Janicaud
  • 3,531
  • 1
  • 12
  • 18
0

I've created library that uses recursive walk and one of its method is exactly what you need.

https://github.com/dominik791/obj-traverse

Use findFirst() method. The first parameter is a root object, not array, so you should create it at first:

var tree = {
  text: 'rootObj',
  nodes: [
  {
    text: 'Parent 1',
    id: 1,
    nodes: [
      {
        'text': 'Child 1',
        id: 2,
        nodes: [ ... ]
      },
      {
        'name': 'Child 2',
        id: 3,
        nodes: [ ... ]
      }
    ]
  },
  {
    text: 'Parent2',
    id: 6
  }
};

Then:

var objToEdit = findFirst(tree, 'nodes', { id: 11 });

Now objToEdit is a reference to the object that you want to edit. So you can just:

objToEdit.text = 'Granchild 13435';

And your tree is updated.

dominik791
  • 692
  • 6
  • 17