Recursion in a table using razor in ASP.NET Core

2019-08-21 08:13发布

I have this product category model:

public class ProductCategory
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Title { get; set; }
}

Using the parent Id, I want to display a list of categories and sub-categories (max three levels) in a tabeled list, like so:

<table>
    <tr><td colspan="3">Category #1</td></tr>
    <tr><td></td><td>Category #1.1</td><td></td></tr>
    <tr><td></td><td>Category #1.2</td><td></td></tr>
    <tr><td colspan="2"></td><td>Category #1.2.1</td></tr>
    <tr><td colspan="2"></td><td>Category #1.2.2</td></tr>
    <tr><td colspan="3">Category #2</td></tr>
</table>

I tried to implement this solution, but I don't understand how I'm supposed to pass the data to the partial view. And my categories don't have a reference to children, but rather to parents.

1条回答
男人必须洒脱
2楼-- · 2019-08-21 08:37

To mimic the solution you refer to, you'd have to add at least one Navigation Property to your entity. This way you can effectively enumerate the children of each ProductCategory.

I would suggest the following entity declaration, which would cause no extra side effects in the database. It has two Navigation properties for convenience:

public class ProductCategory
{
    public int Id { get; set; }
    public string Title { get; set; }

    [ForeignKey(nameof(ParentCategory))]
    public int? ParentId { get; set; }

    public ProductCategory ParentCategory { get; set; } //nav.prop to parent
    public ICollection<ProductCategory> Children { get; set; } //nav. prop to children
}

Now, if you have a nicely filled database set with ParentCategory records, you could query it in an action method as follows:

public IActionResult Index()
{
    //get all categories, so we have each and every child in Context
    var categories = yourDbContext.ProductCategories.Include(e => e.Children).ToList();
    //only need top level categories in the View
    var topLevelCategories = categories.Where(e => e.ParentId == null);

    return View(topLevelCategories);
}

This view would then take these top level categories as a model (I would strongly recommend creating a ViewModel for this), and use a Partial to render all children recursively:

@model IEnumerable<ProductCategory>

<table>
    @Html.Partial("CategoryRowPartial", Model)
</table>

Finally, the CategoryRowPartial, which also receives an IEnumerable<ProductCategory> would look like this. It calls itself recursively to display all children:

@model IEnumerable<ProductCategory>

@foreach (var category in Model)
{
    <tr><td>@category.Title</td></tr>
    @Html.Partial("CategoryRowPartial", category.Children)
}

Now, this doesn't take into account the level of each child nor the empty (and rather sloppy) td's & colspans. Personally, I'd use <ul> or <ol> for this. They are meant to be used to display hierarchies.

If you insist on using a <table>, I again recommend to create a specialized View Model which could hold the "depth" of each table row.

查看更多
登录 后发表回答