2

i am trying to loop through multilevel dynamic menus. I have been succeeded to do this manually i.e everytime if want to display the child Menus of it's parent, I have to loop manually. I would like to know the best way or an alternative of looping multi-level through these dynamic menus Here is what i have done so far;

@{ var menusList = ViewBag.Menus as IEnumerable<ParentMenuViewModel>; }
@foreach (var parentMenu in menusList.Where(p => p.ParentId == 0))
{
    <ul>
        <li>
            <h1>@parentMenu.Name</h1>
            @if (menusList.Count(p => p.ParentId == parentMenu.MenuId) > 0)
            {
                <ul>
                    @foreach (var childMenu in menusList.Where(p => p.ParentId == parentMenu.MenuId))
                    {
                        <h2>@childMenu.Name</h2>
                        if (menusList.Count(p => p.ParentId == childMenu.MenuId) > 0)
                        {
                            foreach (var subChild in menusList.Where(p => p.ParentId == childMenu.MenuId))
                            {
                                <h3>@subChild.Name</h3>
                            }
                        }
                    }
                </ul>
            }
        </li>
    </ul>

}

UPDATE: The output looks like this;

HOME
 SUB MENU1
  SUB SUB MENU1
  SUB SUB MENU2

However, i have in my database something like this;

HOME
 SUB MENU1
  SUB SUB MENU1
  SUB SUB MENU2
    Sub SUB SUB MENU1
    Sub SUB SUB MENU2

Here is my model;
enter image description here

1 Answer 1

8

You could use a partialview and then do a recursive loop. In order to do that you'd first need to change your Model a bit:

ViewModel

// The ViewModel is now a hirearchical model, where each item has a list of children.
public class MenuViewModel
{
    int MenuId {get; set;}
    string Name {get; set;}
    //other properties
    ** snip ** 
    List<MenuViewModel> Children {get; set;}
}

Controller

Transform model into the hierarchical ViewModel:

public ActionResult Menus(){
    List<Menu> menusource; // get your menus here
    ViewBag.Menus = CreateVM(0, menusource);  // transform it into the ViewModel
    return View();
}

public IEnumerable<MenuViewModel> CreateVM(int parentid, List<Menu> source)
{
    return from men in source
           where men.ParentId = parentid
           select new MenuViewModel(){
                      MenuId = men.MenuId, 
                      Name = men.Name
                      // other properties
                      Children = CreateVM(men.MenuId, source)
                  };
}

View

@{ 
    var menusList = ViewBag.Menus as IEnumerable<MenuViewModel>; 
    Html.RenderPartial("MenuPartial", menuslist);
}

MenuPartial

@model IEnumerable<MenuViewModel>

@foreach (var menuitem in model)
{
    <ul>
        <li>
            <h1>@menuitem.Name</h1>
            @{
                Html.RenderPartial("MenuPartial", menuitem.Children);
            }
        </li>
    </ul>
}

The only thing you will be missing here with regards to your original code is that you don't have different Hx-tags, but you could find a way around that by creating another viewmodel and passing it the level you are currently at.

Note: I typed up all this code in the SO-editor, so there may be some small syntax errors.

Sign up to request clarification or add additional context in comments.

2 Comments

can you make it asycronous( your code). i tried but didn't succed. Using async and await keywords
partially right. How you are rendering in view is not seems correct

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.