Search code examples
.net-corenested-loopsrazor-pagespartial-views

How do I list an indefinite number of nested categories and subcategories with a partial view.(.NET CORE 5.0)


I am new to programming. I want to list the categories whose nested number is not clear. As a result of my research, I decided that I could do it in a single Database table. I thought I should use a recursive structure for this and decided to use partialview for it.

DB Entity

public class Categories {
    public int ID { get; set; }
    public int ParentCatID { get; set; }
    public string CategoryName { get; set; }
    public string Instruction { get; set; }
}

PartialView I am trying to write

enter image description here

Can I do it without using PartialView?

I want to achieve this output

enter image description here


Solution

  • class

    public class Categories
    {
        public int ID { get; set; }
    
        public int? ParentCatID { get; set; }
    
        public Categories ParentCat { get; set; }
    
        public string CategoryName { get; set; }
    
        public string Instruction { get; set; }
    
        public IList<Categories> Children { get; protected set; } = new List<Categories>();
    }
    

    ViewModel

    public class CategoriesViewModel
    {
        public CategoriesViewModel()
        {
            ChildItems = new List<CategoriesViewModel>();
        }
    
        public long ID { get; set; }
    
        public string CategoryName { get; set; }
    
        public string Instruction { get; set; }
    
        public CategoriesViewModel ParentCatID { get; set; }
    
        public IList<CategoriesViewModel> ChildItems { get; set; }
    
        public void AddChildItem(CategoriesViewModel childItem)
        {
            childItem.ParentCatID = this;
            ChildItems.Add(childItem);
        }
    }
    

    controller

    public IActionResult List()
    {
        var categories = _context.ToList(); // example
    
        var categoryItems = new List<CategoriesViewModel>();
    
        var topCategories = categories.Where(x => !x.ParentCatID.HasValue);
        foreach (var category in topCategories)
        {
            var categoryMenuItem = Map(category);
            categoryItems.Add(categoryMenuItem);
        }
    
        return View(categoryItems);
    }
    
    private CategoriesViewModel Map(Categories category)
    {
        var categoryMenuItem = new CategoriesViewModel
        {
            ID = category.ID,
            CategoryName = category.CategoryName,
            Instruction = category.Instruction
        };
    
        var childCategories = category.Children;
        foreach (var childCategory in childCategories)
        {
            var childCategoryMenuItem = Map(childCategory);
            categoryMenuItem.AddChildItem(childCategoryMenuItem);
        }
    
        return categoryMenuItem;
    }
    

    view

    @model IEnumerable<CategoriesViewModel> 
        
    @foreach (var item in Model)
    {
        if (item.ChildItems.Any())
        {
            <li>
                <span>@item.CategoryName</span>
                <ul class="dropdown">
                    <li>
                        @foreach (var childItem in item.ChildItems)
                        {
                            <span>@childItem.CategoryName</span>
                        }
                    </li>
                </ul>
            </li>
        }
        else
        {
            <li><span>@item.CategoryName</span></li>
        }
    }