0

I am trying to show nested data in ul/li, but nested children are not showing. See my code and please tell me what is wrong there.

Controller:

public ActionResult Index()
{       
    List<MenuItem> allMenu = new List<MenuItem>
    {
        new MenuItem {Id=1,Name="Parent 1", ParentId=0},
        new MenuItem {Id=2,Name="child 1", ParentId=1},
        new MenuItem {Id=3,Name="child 2", ParentId=1},
        new MenuItem {Id=4,Name="child 3", ParentId=1},
        new MenuItem {Id=5,Name="Parent 2", ParentId=0},
        new MenuItem {Id=6,Name="child 4", ParentId=4}
    };

    List<MenuItem> mi = allMenu
    .Where(e => e.ParentId == 0) /* grab only the root parent nodes */
    .Select(e => new MenuItem
    {
        Id = e.Id,
        Name = e.Name,
        ParentId = e.ParentId,
        Children = allMenu.Where(x => x.ParentId == e.Id).ToList()
    }).ToList();

    ViewBag.menusList = mi;

    return View();
}

POCO class:

public class MenuItem 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int ParentId { get; set; }
    public virtual List<MenuItem> Children { get; set; }
}

View:

@helper ShowTree(List<Scaffolding.Controllers.MenuItem> menusList)
{
    <ul>
        @foreach (var item in menusList)
        {
            <li>
                <span>@item.Name</span>
                @if (item.Children != null && item.Children.Any())
                {
                    @ShowTree(item.Children)
                }
            </li>
        }
    </ul>
}

@{
    var menuList = ViewBag.menusList as List<Scaffolding.Controllers.MenuItem>;
    @ShowTree(menuList);
}

If you run the code then you will see child 4 is not showing which is a child of child 3. Please advise what I need to change in my code. Thanks

4
  • 1
    possible duplicate of stackoverflow.com/questions/49392969/… Commented Mar 22, 2018 at 16:20
  • If "child 4" is a child of "child 3" but "child 3" is itself a child (and therefore has a ParentId that is not zero then this line .Where(e => e.ParentId == 0) will filter it out and it never gets its Children property populated like you need. Commented Mar 22, 2018 at 16:48
  • Additionally, even if you removed the where clause you'd still have the issue that you'd need to make multiple passes at it to get the MenuItems recursively nested like you need properly. Commented Mar 22, 2018 at 16:52
  • @Shelby115 can you please rectify my code which will work for nth nesting because nothing comes to mind like where to change in code. thanks Commented Mar 22, 2018 at 19:51

2 Answers 2

1

Your query gets the top level elements (ParentId == 0) only and then populate just their direct child elements.

Your query needs to be changed to populate all child elements for all levels. Note that your MeuItem does not need the ParentId property.

// Group the items by parentId and project to MenuItem
var groups = allMenu.ToLookup(x => x.ParentId, x => new MenuItem
{
    Id = x.Id,
    Name = x.Name,
});
// Assign the child menus to all items
foreach (var item in allMenu)
{
    item.children = groups[item.Id].ToList();
}
// Return just the top level items
ViewBag.menusList = groups[0].ToList();

As a side note, do not use ViewBag. Pass the model to the view instead

return View(groups[0].ToList());

and in the view

@model List<MenuItem>
....
@ShowTree(Model);
Sign up to request clarification or add additional context in comments.

6 Comments

thanks for your answer sir. now i could fix the problem. problem was main in razor logic which i could fix and take help from this link mikesdotnetting.com/article/208/… thanks a lot for your suggestion and support.
You do not need to change the @helper code in your original question (and your own answer makes no sense and is not even correct)
sir i just checked the code and now it is working. please come with a example that why you are saying not correct if possible ?
You did not even find this answer useful! (but the @helper code in your question does not need to be changed)
Its effectively a .GroupBy() which is executed immediately - refer this answer for a detailed explanation
|
0

Now i could fix my problem. the problem was in logic of razor code and also i comment this line //.Where(e => e.ParentId == 0) here i am adding working code.

@helper  ShowTree(List<NestedChild.Controllers.MenuItem> menu, int? parentid = 0, int level = 0)
{
    var items = menu.Where(m => m.ParentId == parentid);

    if (items.Any())
    {
        if (items.First().ParentId > 0)
        {
            level++;
        }

        <ul>
            @foreach (var item in items)
            {
            <li>
                @item.Name
            </li>
                @ShowTree(menu, item.Id, level);
            }
        </ul>
    }
}
@{
    var menuList = ViewBag.menusList as List<NestedChild.Controllers.MenuItem>;
    @ShowTree(menuList);
}

Action

public ActionResult Index()
{
    List<MenuItem> allMenu = new List<MenuItem>
    {
        new MenuItem {Id=1,Name="Parent 1", ParentId=0},
        new MenuItem {Id=2,Name="child 1", ParentId=1},
        new MenuItem {Id=3,Name="child 2", ParentId=1},
        new MenuItem {Id=4,Name="child 3", ParentId=1},
        new MenuItem {Id=5,Name="Parent 2", ParentId=0},
        new MenuItem {Id=6,Name="child 4", ParentId=4}
    };

    List<MenuItem> mi = allMenu
    //.Where(e => e.ParentId == 0) /* grab only the root parent nodes */
    .Select(e => new MenuItem
    {
        Id = e.Id,
        Name = e.Name,
        ParentId = e.ParentId,
        Children = allMenu.Where(x => x.ParentId == e.Id).ToList()
    }).ToList();

    ViewBag.menusList = mi;

    return View();
}

Comments

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.