How can i create a multi level menu in MVC core?

守給你的承諾、 提交于 2021-02-10 14:33:19

问题


The HTML menu rendered from my helper function is

  • Category 1
    • Category 2
  • Category 2
  • Category 3
  • Category 4

I have set Category 2 as a child category of Category 1.

Unfortunately, the current HTML helper displays again Category 2 as a parent afterwards.

Id  ParentCategoryId Description
1   NULL             Category 1
2   1                Category 2 
3   NULL             Category 3 
4   NULL             Category 4 
5   NULL             Category 5

How should I modify my helper function?

@{ Func<dynamic, IHtmlContent> ShowMenu(List<Category> cats) =>
    @<ul>
        @foreach (var cat in cats)
        {
            <li>
                @cat.Description
                @if (cat.Childs != null && cat.Childs.Any())
                {
                    @ShowMenu(cat.Childs)(null)
                }
            </li>
        }
    </ul>; 
}

The category model used is as

public class Category
{
    public int Id { get; set; }

    public int? ParentCategoryId { get; set; }
    public Category ParentCategory { get; set; }

    [ForeignKey("ParentCategoryId")]
    public List<Category> Childs { get; set; }

    public string Description { get; set; }
}

The html menu is displayed in razor via

@ShowMenu(Model.Categories)(null)

where

Model.Categories = context.Categories.ToList()

Update: Thanks to the helpfull answers given, it seems i should also pass the parent category as a parameter.

@{ Func<dynamic, IHtmlContent> ShowMenu(List<Category> cats, Category parent) =>
@<ul>
    @foreach (var cat in cats)
    {
        <li>
            @cat.Description
            @if (cat.Childs != null && cat.Childs.Any())
            {
                @ShowMenu(cat.Childs, cat)(null)
            }
        </li>
    }
</ul>; }

回答1:


cats holds all your categories, apparently. Note that your function will show all the elements of your list, so, if your outer list contains all elements, even the inner elements, then the issue you experience happens. Now, a simple solution is to change your function, so that it receives a Category parent parameter as well and you pass a null at the outer call and cat at the recursive call. Now, wrap an if around your <li></li> node, to check whether ParentCategoryId matches the parent param's value we have just discussed. If that condition evaluates to true, then the li will be displayed. If not, then it will not be displayed.

EDIT

I have wrapped the if I suggested around the logic. Since I am unfamiliar with this syntax, it is possible that the code below is not the way this should be written, but I'm convinced that the idea behind this code is the one that needs to be applied.

@{ Func<dynamic, IHtmlContent> ShowMenu(List<Category> cats, Category parent) =>
@<ul>
    @foreach (var cat in cats)
    {
        @if (((parent == null) && (cat.ParentCategoryId == null)) || (parent?.Id == cat.ParentCategoryId)))
        {
            <li>
                @cat.Description
                @if (cat.Childs != null && cat.Childs.Any())
                {
                    @ShowMenu(cat.Childs, cat)(null)
                }
            </li>
        }
    }
</ul>; }



回答2:


Only pass the roots categories like this:

 Model.Categories = context.Categories.Where(c => c.ParentCategoryId == null).ToList()


来源:https://stackoverflow.com/questions/65868971/how-can-i-create-a-multi-level-menu-in-mvc-core

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!