Search code examples
jqueryhtmlrandommenusubmenu

Generate 7 level menu structure with jQuery


I have to dynamically create simple UL/LI menu structure with random number of items for all 7 levels. I need this for testing CSS styling.

Now, I wrote jQuery code for this purposes:

jQuery(document).ready(function($){
var menu = [];
var number = 5 + Math.floor(Math.random() * 5);
for (var i = 1; i <= number; i++) {
    if ( Math.round(Math.random()) == 1 ) {
        var submenu1 = [];
        for ( var a = 1; a <= (4 + Math.floor(Math.random() * 5)); a++ ) {
            if ( Math.round(Math.random()) == 1 ) {
                var submenu2 = [];
                for ( var b = 1; b <= (3 + Math.floor(Math.random() * 5)); b++ ) {
                    if ( Math.round(Math.random()) == 1 ) {
                        var submenu3 = [];
                        for ( var c = 1; c <= (3 + Math.floor(Math.random() * 4)); c++ ) {
                            if ( Math.round(Math.random()) == 1 ) {
                                var submenu4 = [];
                                for ( var d = 1; d <= (3 + Math.floor(Math.random() * 3)); d++ ) {
                                    if ( Math.round(Math.random()) == 1 ) {
                                        var submenu5 = [];
                                        for ( var e = 1; e <= (3 + Math.floor(Math.random() * 2)); e++ ) {
                                            if ( Math.round(Math.random()) == 1 ) {
                                                var submenu6 = [];
                                                for ( var f = 1; f <= (3 + Math.floor(Math.random() * 1)); f++ ) {
                                                    submenu6.push('<li class="item"><a href="#">Item '+f+'</a></li>');
                                                }
                                                parent6 = "parent";
                                                subitems6 = '<ul class="submenu">'+submenu6.join('')+'</ul>';
                                            } else {
                                                parent6 = subitems6 = "";
                                            }
                                            submenu5.push('<li class="item"><a href="#">Item '+e+'</a>'+subitems6+'</li>');
                                        }
                                        parent5 = "parent";
                                        subitems5 = '<ul class="submenu">'+submenu5.join('')+'</ul>';
                                    } else {
                                        parent5 = subitems5 = "";
                                    }
                                    submenu4.push('<li class="item '+parent5+'"><a href="#">Item '+d+'</a>'+subitems5+'</li>');
                                }
                                parent4 = "parent";
                                subitems4 = '<ul class="submenu">'+submenu4.join('')+'</ul>';
                            } else {
                                parent4 = subitems4 = "";
                            }
                            submenu3.push('<li class="item '+parent4+'"><a href="#">Item '+c+'</a>'+subitems4+'</li>');
                        }
                        parent3 = "parent";
                        subitems3 = '<ul class="submenu">'+submenu3.join('')+'</ul>';
                    } else {
                        parent3 = subitems3 = "";
                    }
                    submenu2.push('<li class="item '+parent3+'"><a href="#">Item '+b+'</a>'+subitems3+'</li>');
                }
                parent2 = "parent";
                subitems2 = '<ul class="submenu">'+submenu2.join('')+'</ul>';
            } else {
                parent2 = subitems2 = "";
            }
            submenu1.push('<li class="item '+parent2+'"><a href="#">Item '+a+'</a>'+subitems2+'</li>');
        }
        parent1 = "parent";
        subitems1 = '<ul class="submenu">'+submenu1.join('')+'</ul>';
    } else {
        parent1 = subitems1 = "";
    }
    menu.push('<li class="item '+parent1+'"><a href="#">Item '+i+'</a>'+subitems1+'</li>');
}
$("#topnav").html('<ul class="menu">'+menu.join('')+'</ul>');
});

My question is: is there some better (shorter) solution to achieve this goal?

btw, JSFiddle for this case is here http://jsfiddle.net/urosevic/Fy5jr/ where you can see how that code works. So, I'll love to learn how to optimize that JS code.

Thank you!


Solution

  • Here is the example with recursive creation of elements:

    function createBranch(currentNode) {
        var numberOfParents = currentNode.parents("li").length;
    
        //if we don't reach deepest level - we can add submenu
        if(numberOfParents < MAX_NESTING_LEVEL-1) {
            //decide, should we create submenu for current <li>
            if (Math.round(Math.random()) == 1) {
                //create <ul> submenu
                var ul = $("<ul />", {
                    class: "submenu"
                });
    
                currentNode.append(ul);
    
                //adding children <li> to submenu
                var childNumber = getRandomInt(MIN_CHILD_NUMBER, MAX_CHILD_NUMBER);
                for(var i = 0; i < childNumber; i++) {
                    var li = createLeaf(i);
                    ul.append(li);
    
                    //using recursion: submenu creation for current <li>
                    createBranch(li);
                }
            }
        }
        return currentNode;
    }
    

    Here are two functions that could use recursion for different purposes:

    /**could generate empty (nothing will be added to "#topnav")*/
    function randomMenu() {
        var generated = createBranch($("#topnav"));
    
        generated.find("ul").parent("li").addClass("parent");
    
        generated.children("ul").removeClass("submenu").addClass("menu");
    }
    

    and

    function menuWithConstantNumberOfRootListItems(rootListItemsNumber){
        var root = $("<ul/>", {class:"menu"});
    
        //generate root <ul> with needed quantity of <li>
        for(var i = 0; i < rootListItemsNumber; i++) {
            var rootLeaf = createLeaf(i);
            root.append(rootLeaf);
            createBranch(rootLeaf);
        }
    
        root.find("ul").parent("li").addClass("parent");
    
        $("#topnav").append(root);
    }
    

    There are additional functions (getRandomInt and createLeaf) and variables (MAX_NESTING_LEVEL, MIN_CHILD_NUMBER and MAX_CHILD_NUMBER), you can check their usage in the DEMO.