问题
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