Skip to content Skip to sidebar Skip to footer

Create A Nested Ul Menu Based On The Url Path Structure Of Menu Items

I have an array of menu items, each containing Name and URL like this: var menuItems = [ { name : 'Store', url : '/store' }, { nam

Solution 1:

I think the best solution is firstly to convert your data structure to a tree one, with parent/children relations. Render this structure will then be easier, as the UL itself has a tree structure.

You can convert menuItems using these couple of functions

// Add an item node in the tree, at the right positionfunctionaddToTree( node, treeNodes ) {

    // Check if the item node should inserted in a subnodefor ( var i=0; i<treeNodes.length; i++ ) {
        var treeNode = treeNodes[i];

        // "/store/travel".indexOf( '/store/' )if ( node.url.indexOf( treeNode.url + '/' ) == 0 ) {
            addToTree( node, treeNode.children );

            // Item node was added, we can quitreturn;
        }
    }

    // Item node was not added to a subnode, so it's a sibling of these treeNodes
    treeNodes.push({
        name: node.name,
        url: node.url,
        children: []
    });
}

//Create the item tree starting from menuItemsfunctioncreateTree( nodes ) {
    var tree = [];

    for ( var i=0; i<nodes.length; i++ ) {
        var node = nodes[i];
        addToTree( node, tree );
    }

    return tree;
}

var menuItemsTree = createTree( menuItems );
console.log( menuItemsTree );

The resulting menuItemsTree will be an object like this

[{"name":"Store","url":"/store","children":[{"name":"Travel","url":"/store/travel","children":[]},{"name":"Gardening","url":"/store/gardening","children":[]},{"name":"Healthy Eating","url":"/store/healthy-eating","children":[{"name":"Cook Books","url":"/store/healthy-eating/cook-books","children":[]},{"name":"Single Meal Gifts","url":"/store/healthy-eating/single-meal-gifts","children":[]}]},{"name":"Outdoor Recreation","url":"/store/outdoor-recreation","children":[{"name":"Hiking","url":"/store/outdoor-recreation/hiking","children":[{"name":"Snowshoeing","url":"/store/outdoor-recreation/hiking/snowshoeing","children":[]}]},{"name":"Skiing","url":"/store/outdoor-recreation/skiing","children":[]}]},{"name":"Physical Fitness","url":"/store/physical-fitness","children":[]},{"name":"Provident Living","url":"/store/provident-living","children":[]}]}]

You mentioned you already have html renderer for trees, right? If you need further help let us know!

Solution 2:

12 simple lines of code:

var rootList = $("<ul>").appendTo("body");
var elements = {};
$.each(menuItems, function() {
    var parent = elements[this.url.substr(0, this.url.lastIndexOf("/"))];
    var list = parent ? parent.next("ul") : rootList;
    if (!list.length) {
        list = $("<ul>").insertAfter(parent);
    }
    var item = $("<li>").appendTo(list);
    $("<a>").attr("href", this.url).text(this.name).appendTo(item);
    elements[this.url] = item;
});

http://jsfiddle.net/gilly3/CJKgp/

Solution 3:

Although I like the script of gilly3 the script produces list with different element nesting of <li> and <ul> than was originally asked. So instead of

<li><ahref="/store">Store</a><ul><li><ahref="/store/travel">Travel</a></li>
        ...
     </ul></li>
It produces
<li><ahref="/store">Store</a></li><ul><li><ahref="/store/travel">Travel</a></li>
      ...
   </ul>
This may cause incompatibilities for utilities or frameworks working with such generated menu and producing interactive menu with animation (e.g. superfish.js). So I updated the 12 lines script
var rootList = $("<ul>").appendTo("body");
var elements = {};
$.each(menuItems, function() {
    var parent = elements[this.url.substr(0, this.url.lastIndexOf("/"))];
    var list = parent ? parent.children("ul") : rootList;
    if (!list.length) {
        list = $("<ul>").appendTo(parent);
    }
    var item = $("<li>").appendTo(list);
    $("<a>").attr("href", this.url).text(this.name).appendTo(item);
    elements[this.url] = item;
});

http://jsfiddle.net/tomaton/NaU4E/

Solution 4:

It's not in jQuery, but maybe this could help. I developed this after seeking the web to do exactly what you want.

http://www.chapleau.info/article/ArrayofUrlsToASitemap.html

Solution 5:

Or maybe complete jQuery plugin http://jsfiddle.net/9FGRC/

(EDIT)

An update to previous version http://jsfiddle.net/9FGRC/1/

This version supports following case

var menuItems = [  
    {  
        name : "Store",  
        url : "/store"  
    },  
    {  
        name : "Cook Books",  
        url : "/store/healthy-eating/cook-books"  
    },  
    {  
        name : "Single Meal Gifts",  
        url : "/store/healthy-eating/single-meal-gifts"  
    }  
]  

Since there is skipped

    {  
        name : "Healthy Eating",  
        url : "/store/healthy-eating"  
    },

It will produce following html

<ul><li><ahref="/store">Store</a><ul><li><ahref="/store/healthy-eating/cook-books">Cook Books</a></li><li><ahref="/store/healthy-eating/single-meal-gifts">Single Meal Gifts</a></li></ul></li></ul>

I guess it won't be the case, but could be helpful to someone

Post a Comment for "Create A Nested Ul Menu Based On The Url Path Structure Of Menu Items"