-1

Hi I am using JavaScript and jQuery as client side script. I am little bit new to Recursive functions. I have a JSON data as below and I have tried to make a tree structure using below JSON data by writing a recursive function but I am not able to build the tree structure.

var jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }

Required Output:

var treeNode = {
                    id: 101, // random
                    text: object.name,
                    icon: "fas fa-plus",
                    subNode: {
                        // id, text, icon and subNode of Children object
                        // recursive data,  So on.... 
                    }
                };

Can anyone suggest me or help me to write javascript or jQuery Recursive function based on above JSON data so I can build tree structure. I know I am asking about help because I do have less knowledge about recursive function.

prog1011
  • 3,157
  • 3
  • 20
  • 49

2 Answers2

0

If we abstract this a bit, it's pretty easy to write a general-purpose tree-mapping function. Then we can supply two callback functions: one to find the child nodes of the input and one to build the output node based on the input and the mapped children. Such a function turns out to be surprisingly simple:

const mapTree = (getChildren, transformNode) => (tree) =>
  transformNode (
    tree, 
    (getChildren (tree) || []) .map (mapTree (getChildren, transformNode))
  )

For your data, getChildren is simply (node) => node._children

And the node transformation might be as simple as:

const transformNode = (node, children) => 
  ({
    id: node.$id,         // or a randomizing call?
    text: node.name,
    icon: "fas fa-plus",  // is this really a fixed value?
    subNode: children
  })

Putting this together we get

const mapTree = (getChildren, transformNode) => (tree) =>
  transformNode (
    tree, 
    (getChildren (tree) || []) .map (mapTree (getChildren, transformNode))
  )

const kids = (node) => node._children

const transformNode = (node, children) => 
  ({
    id: node.$id,
    text: node.name,
    icon: "fas fa-plus",    
    subNode: children
  })

const myTransform = mapTree (kids, transformNode)

const jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }

console .log (myTransform (jsonData))

This does something slightly different from your requested output. You had written subNode: { ... }, but instead I'm returning an array of objects, subNodes: [ ... ], as I don't make any real sense of a plain object here.

Also, this will yield an empty subNodes array if an input node has no children. If you would rather not have the subNodes property, you could replace

    subNode: children

with something like

    ...(children .length ? {subNode: children} : {})

Obviously, you don't need the named helpers and could call mapTree with anonymous functions like this:

const myTransform = mapTree (
  (node) => node._children, 
  (node, children) => 
    ({
      id: node.$id,
      text: node.name,
      icon: "fas fa-plus",    
      subNode: children
    })
)

This mapTree function was very easy to write, as I didn't have to think about any details of the output or input formats as I wrote it. But perhaps that abstraction is not helpful to me, and I'm never going to use it except here. If so, I can simply rework the abstract version by plugging the hard-coded callbacks directly. With only a little manipulation, that will turn it into this version:

const newTransform = (node) =>
  ({
    id: node.$id,
    text: node.name,
    icon: "fas fa-plus",    
    subNode: (node._children || []).map(newTransform)
  })

const jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }

console .log (newTransform (jsonData))

There's an important point here. This generic function was much easier to write than if I'd tried to write something to convert your format directly. While there is a danger in too-early abstraction, it also can offer significant benefits. I might well choose to keep only that last version, but the generic abstraction simplified the development of it.

Scott Sauyet
  • 37,179
  • 4
  • 36
  • 82
0

It can be something like that, with using the json data model

<!doctype html>

<html>
  <head>
    <link rel="stylesheet" href="lib/style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  </head>

  <body>
    <div id="myDiv"></div>
  </body>
  <script>

var treeData={
   "Id":"10",
   "text":"Document Categories",
   "icon":"fas fa-plus",
   "subNode":
    [
      {
         "Id":"11",
         "text":"Pdf Documents",
         "icon":"fas fa-plus",
         "subNode":[
            {
               "Id":"31",
               "text":"Book Pdfs",
               "icon":"fas fa-plus",
                "subNode":[]
            },
            {
               "Id":"32",
               "text":"EPub",
               "icon":"fas fa-plus",
               "subNode":[
                  {
                     "Id":"20",
                     "text":"EBook Epubs1",
                     "icon":"fas fa-plus",
                     "subNode":[]
                  },
                  {
                     "Id":"30",
                     "text":"EBook Epubs2",
                     "icon":"fas fa-plus",
                     "subNode":[]
                  }
               ]
            }
         ]
      },
      {
         "Id":"33",
         "text":"Text Documents",
         "icon":"fas fa-plus",
         "subNode":[
            {
               "Id":"32",
               "text":"Book Text",
               "icon":"fas fa-plus",
                "subNode":[]
            },
            {
               "Id":"35",
               "text":"Automatic Text",
               "icon":"fas fa-plus",
               "subNode":[]
            }
         ]
      }
   ]
};

    var newTree = AddRecursive(null, treeData);
    var treeDiv = $('#myDiv');
    treeDiv.append(newTree);


function AddRecursive(tree, data) {
  if (tree == null) {
    tree = $('<ul/>');
    tree.attr('id', 'treeID');
  }

  var listU = $('<ul />');
  listU.addClass('ul class');

  var listItem = $('<li />');
  listItem.addClass('li class');
  listItem.attr('data-id', data.Id);

  var link = $('<a />');
  var i = $('<i/>').addClass('fa fa-folder');
  link.append(i);

  //link.addClass("linkClass");
  link.append(data.text);
  listItem.append(link);

  if (data.subNode.length > 0) {
    var span = $(' <span />');
    span.addClass('fa-chevron-down');
    link.append(span);
  }

  listU.append(listItem);
  tree.append(listU);

  for (i in data.subNode) {
    AddRecursive(listItem, data.subNode[i]);
  }
  return tree;
}



  </script>
</html>
suyelen
  • 1
  • 1