I've been scratching my head on how to get this dynamic menu working in a cleaner way than I currently do, I currently receive a list of menu items as a flat XML structure.
I've created an object below illustrating how the data will look inside an object, it has a parent-child relationship for each menu item (I've indented for ease of reading)
let Menu = [
{
DisplayName : "Menu1",
href : "Menu1.aspx",
MenuID : "1",
ParentMenuID : "?",
Position : "1",
UserTypeCode : "99"
},
{
DisplayName : "Menu-1-1",
href : "Menu1.aspx",
MenuID : "2",
ParentMenuID : "1",
Position : "1",
UserTypeCode : "99"
},
{
DisplayName : "Menu-1-2",
href : "Menu1.aspx",
MenuID : "3",
ParentMenuID : "1",
Position : "2",
UserTypeCode : "99"
},
{
DisplayName : "Menu2",
href : "Menu2.aspx",
MenuID : "4",
ParentMenuID : "?",
Position : "2",
UserTypeCode : "99"
},
{
DisplayName : "Menu2-1",
href : "Menu1.aspx",
MenuID : "5",
ParentMenuID : "4",
Position : "1",
UserTypeCode : "99"
},
{
DisplayName : "Menu2-2",
href : "Menu1.aspx",
MenuID : "6",
ParentMenuID : "4",
Position : "2",
UserTypeCode : "99"
},
{
DisplayName : "Menu2-2-1",
href : "Menu1.aspx",
MenuID : "7",
ParentMenuID : "6",
Position : "1",
UserTypeCode : "99"
}
];
I would like to know how I could dynamically create the menu object (using a recursive function I believe would be ideal) without my current somewhat messy solution of requiring a different function for each level of my menu, Here is what my code looks like at the minute, It is limited to only 3 levels of menu's
What I desire is a nice function where it will accept any number of menu levels
function createRoot(){
// Initially map all root elements
Menu.map((item, index) => {
if (item.ParentMenuID === "?"){
// If the the next menu item is a child of this root
if (Menu[index+1].ParentMenuID === item.MenuID){
// Generate boilerplate dropdown code + then retrieve it's children
htmlStr += `<li class="dropdown-submenu"><a class="test" data-menuID="`+item.MenuID+`" data-menuitem="`+item.href+`" href="#">`+item.DisplayName+`<span class="caret"></a>`
htmlStr += `<ul class="dropdown-menu">`
GetLevel1(item);
htmlStr += `</ul>`
htmlStr += `</li>`
// Otherwise it's just a normal menu item
} else {
htmlStr += `<li><a class="test" data-menuID="`+item.MenuID+`" data-menuitem="`+item.href+`" href="#">`+item.DisplayName+`</a></li>`
}
}
});
$('#user-menu-list').html(htmlStr);
// Setup event on list items
$('.dropdown-submenu a.test').on("click", function(e){
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
}
function GetLevel1(item){
Menu.map((subItem, index) => {
if (index < Menu.length-1){
console.log(index);
// If the current item is a child of the root
if (subItem.ParentMenuID === item.MenuID){
// If the the next item is a child of this root
if (Menu[index+1].ParentMenuID === subItem.MenuID){
htmlStr += `<li class="dropdown-submenu"><a class="test" data-menuID="`+subItem.MenuID+`" data-menuitem="`+subItem.href+`" href="#">`+subItem.DisplayName+`<span class="caret"></a>`
htmlStr += `<ul class="dropdown-menu">`
GetLevel2(subItem);
htmlStr += `</ul>`
htmlStr += `</li>`
} else {
htmlStr += `<li><a class="test" data-menuID="`+subItem.MenuID+`" data-menuitem="`+subItem.href+`" href="#">`+subItem.DisplayName+`</a></li>`
}
}
}
});
}
function GetLevel2(item){
Menu.map((subItem, index) => {
console.log("INDEX: "+index);
// If the current item is a child of the root
if (subItem.ParentMenuID === item.MenuID){
htmlStr += `<li><a class="test" data-menuID="`+subItem.MenuID+`" data-menuitem="`+subItem.href+`" href="#">`+subItem.DisplayName+`</a></li>`
}
});
}
createRoot();
Here is a full pastebin link with my menu working at the minute: http://pastebin.com/ektBQ7kd
Any help would be much appreciated!
My recursive abilities are a bit rusty this can be improved, I would do something like this, First go over all the menu, add children menus to their parents.
After phase one complete and I have menus and submenus in one object, you can do recursive again and build the menu.
Something like this:
var Menu = [{ DisplayName: "Menu1", href: "Menu1.aspx", MenuID: "1", ParentMenuID: "?", Position: "1", UserTypeCode: "99" }, { DisplayName: "Menu-1-1", href: "Menu1.aspx", MenuID: "2", ParentMenuID: "1", Position: "1", UserTypeCode: "99" }, { DisplayName: "Menu-1-2", href: "Menu1.aspx", MenuID: "3", ParentMenuID: "1", Position: "2", UserTypeCode: "99" }, { DisplayName: "Menu2", href: "Menu2.aspx", MenuID: "4", ParentMenuID: "?", Position: "2", UserTypeCode: "99" }, { DisplayName: "Menu2-1", href: "Menu1.aspx", MenuID: "5", ParentMenuID: "4", Position: "1", UserTypeCode: "99" }, { DisplayName: "Menu2-2", href: "Menu1.aspx", MenuID: "6", ParentMenuID: "4", Position: "2", UserTypeCode: "99" }, { DisplayName: "Menu2-2-1", href: "Menu1.aspx", MenuID: "7", ParentMenuID: "6", Position: "1", UserTypeCode: "99" }]; var main = []; function getSiblins(currentNode, currentId) { if (!currentId) { currentNode.children = currentNode.children || new Array(); return getSiblins(currentNode, currentNode.MenuID) } else { for (var j = 0; j < Menu.length; j++) { if (Menu[j].ParentMenuID == currentId) { currentNode.children.push(Menu[j]); } } } if (currentNode.ParentMenuID == "?") { //root menu main.push(currentNode); } } for (var i = 0; i < Menu.length; i++) getSiblins(Menu[i]); function prepareMenu(currentMenu) { var appendHtml = "<li>" + currentMenu.DisplayName + "</li>" for (var i = 0; i < currentMenu.children.length; i++) { appendHtml = appendHtml + "<ul class='children'>" + prepareMenu(currentMenu.children[i]) + "</ul>"; } return appendHtml; } var menuHtml = ""; for (var j = 0; j < main.length; j++) { menuHtml += prepareMenu(main[j]); } document.getElementById("finalMenu").innerHTML = menuHtml;
.children li{ color: blue; } .children .children li { color: green; }
<ul id="finalMenu"> </ul>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.