Create A Nested UL Menu Based On The URL Path Structure Of Menu Items
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 position
function addToTree( node, treeNodes ) {
// Check if the item node should inserted in a subnode
for ( 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 quit
return;
}
}
// 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 menuItems
function createTree( 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;
});
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><a href="/store">Store</a>
<ul>
<li><a href="/store/travel">Travel</a></li>
...
</ul>
</li>
It produces
<li><a href="/store">Store</a>
</li>
<ul>
<li><a href="/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;
});
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.
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><a href="/store">Store</a>
<ul>
<li><a href="/store/healthy-eating/cook-books">Cook Books</a></li>
<li><a href="/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"