Object-oriented – What’s an Elegant and OOP way to create a tree from arrays and render it as a nested UL

javascriptobject-oriented

I have a series of arrays which represent file system paths, so each next value is actually a directory deeper, for example:

var a1 = ["Desktop", "Pictures", "Summer 2011"];

is the equivalent of

Desktop
|-Pictures
  |-Summer 2011

I'm trying to find an elegant way to:

  1. Flatten/merge all the different arrays I have to come up with one object/dictionary/multi-dimensional-array.

  2. Parse the result and render a nested UL (html list) to the page which represents the hierarchy correctly.

  3. Write what I already have in a more 'OOP way'..

I already have a working version:

<!DOCTYPE html>
<html>
    <head></head>
    <body onload="init()">
        <ul id="tree"></ul>
        <script>
            var a = [ "Desktop", "Folder1",  "InnerFolder1" ];
            var b = [ "Desktop", "Folder1",  "Inner 2" ];
            var c = [ "Documents", "Folder 2", "InnerFolder1", "even deepper" ];
            var d = [ "Something Else", "Folder1",  "Inner 2" ];

            var all = [a, b, c, d];
            var Tree = {};
            var ul = document.getElementById("tree");

            function init(){
                for ( var i = 0; i < all.length; i++ ){
                    addToTree(Tree, all[i] );
                }
                createList(Tree, ul);
            }

            //function from http://stackoverflow.com/questions/3663096/how-to-convert-array-to-tree
            function addToTree(tree, array) {
                for (var i = 0, length = array.length; i < length; i++) {
                    tree = tree[ array[i] ] = tree[ array[i] ] || {};
                }
            }

            function createList( obj, _pushTo  ){
                for ( attr in obj ){
                    var _doIHaveChildren = function ( ){
                        for(var prop in obj[attr]) {
                            if (obj[attr].hasOwnProperty(prop)) {
                                return true;
                            }
                        }
                        return false;
                    }
                    var li = document.createElement("li");
                    li.id = attr.toString();
                    li.innerHTML = attr.toString();
                    if ( Tree.hasOwnProperty(attr) ){
                        ul.appendChild(li);
                    } else {
                        _pushTo.appendChild(li);
                    }
                    if ( _doIHaveChildren() === true ){
                        var ul2 = document.createElement("ul");
                        li.appendChild(ul2);
                    }
                    createList( obj[attr], ul2 );
                }
            }
        </script>
    </body>
</html>

Thanks!

EDIT:
I'm starting from strings which represent the paths i.e. "Desktop/Pictures/Summer 2011" which are broken to arrays.

Best Answer

In a simple OO way - i would define all the vars - a, b, c, and d itself as a tree.

a_tree = new tree(a); 

and same for all others. After that i would have have a merge tree command

a_tree.merge_tree(b);
a_tree.merge_tree(c); 

This is just another way to do things. Typically merge_tree should be recursive process.

I think to judge which method has more significant different at all, when you scale up the tree to a large size.