views:

2729

answers:

5

Hi, I would like to generate an HTML tree (preferably UL-LI) from the JSON example below. Does anyone have a simple, recursive JS function (not a framework) that can handle this specific structure? Thanks for your help!

{ "folder" : [ {
    "title" : "1",
    "folder" : [ {
     "title" : "1.1",
     "folder" : [ {
      "title" : "1.1.1",
     } , {
      "title" : "1.1.2",
     } ]
    } ]
} , {
    "title" : "2",
} ] }
+7  A: 
function to_ul (obj) {
  // --------v create an <ul> element
  var f, li, ul = document.createElement ("ul");
  // --v loop through its children
  for (f = 0; f < obj.folder.length; f++) {
    li = document.createElement ("li");
    li.appendChild (document.createTextNode (obj.folder[f].title));
    // if the child has a 'folder' prop on its own, call me again
    if (obj.folder[f].folder) {
      li.appendChild (to_ul (obj.folder[f].folder));
    }
    ul.appendChild (li);
  }
  return ul;
}

Caveat: No error checking! If a 'title' or 'folder' is missing, the whole thing could blow up.

Cheers,

Boldewyn
It's also missing adding the li into the ul. Add a ul.appendChild(li) before the for-loop closes and it should work.
Jani Hartikainen
There is also a problem with validity: The Title of the UL is just appended to it. This is something that is not quite useful.
Boldewyn
OK, resolved! There is no title to go with the UL.
Boldewyn
A: 

@Boldewyn: I believe you can also use a For...In loop instead of a regular For loop to shorten the code a bit. Of course, I don't have much experience using this kind of loop, so please check my code snippet.

for (var i in obj.folder) {
    li = document.createElement ("li");
    li.appendChild (document.createTextNode (i.title));
    // if the child has a 'folder' prop on its own, call me again
    if (i.folder) {
      li.appendChild (to_ul (i.folder));
    }
}
thezachperson31
Yes, that would do it, too.
Boldewyn
I included it in my answer, thanks!
Boldewyn
Nope, took it out again. The i would contain the range 0..n and not the array items.
Boldewyn
+1  A: 

I had a problem getting my browser to accept the data structure submitted by the OP, but here is a fully working example I've drawn up for my own, similar purposes. Beside the function I provide the data structure as well, with name/branches instead of title/folder.

<html>
<head>
<script>
function to_ul(branches) {
    var ul = document.createElement("ul");

  for (var i=0, n=branches.length; i<n; i++) {
      var branch = branches[i];
      var li = document.createElement("li");

     var text = document.createTextNode(branch.name);
     li.appendChild(text);

     if (branch.branches) {
       li.appendChild(to_ul(branch.branches));
     }

     ul.appendChild(li);
    }

    return ul;
}

function renderTree() {
  var treeEl = document.getElementById("tree");

    var treeObj = {"root": [{
     "name": "George & Sarah Trede",
     "branches": [{
       "name": "George & Frances Trede",
      "branches" : [{
        "name": "Mary (Trede) Jempty"
      },{
        "name": "Carol (Trede) Moeller"
      }]
     },{
       "name": "Mary (Trede) Sheehan"
     },{
       "name": "Ward Trede"
     }]
  }]};

    treeEl.appendChild(to_ul(treeObj.root));
}
</script>
</head>

<body onload="renderTree()">
<div id="tree">
</body>

</html>
George Jempty
A: 

rSupplant does this. http://philrathe.com/projects/rsupplant

It works with arrays of objects. In your case:

[
    {
        title: "1",
        folder: [
            {
                title: "1.1",
                folder: [
                    {
                        title: "1.1.1"
                    },
                    {
                        title: "1.1.2"
                    }
                ]
            }
        ]
    },
    {
        title: "2"
    }
]
Philippe Rathé
+1  A: 

I've used PURE with some success in the past for this kind of thing.

Surya