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.
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.