Ahmad Alaa
Ahmad Alaa

Reputation: 817

Unlimited nested categories

I have categories table, see its design:

And I want to display this nested categories inside dropdown list like this image:

Can anybody help me to find a solution?

Upvotes: 1

Views: 1643

Answers (1)

CharlieBrown
CharlieBrown

Reputation: 4163

You should retrieve all your categories, ordered by ParentId and then by Name if you need that. You should do this either in your controller or better trough a Service layer that talks to your repository or EntityFramework Datacontext. You didn't specify your data access strategy.

Then in your controller, you'll have to iterate over all categories and create each item taking into account the parent relationship. For example, if you iterate over "top categories" you could then add all child categories of the current category. If you have more than 1 level nesting, you would have to use recursion.

Pseudo-code written directly here, probably won't compile as-is:

//Assume you want to produce a SelectList to use in your View, let's use a view model like the following
public class CategoryViewModelItem
{
   public string Value {get;set;}
   public string Text {get;set;}
}

In your controller/service layer:

List<CategoryViewModelItem> items = new List<CategoryViewModelItem>();

//get all of them from DB
List<Category> allCategories = dataContext.Categories.ToList();
//get parent categories
List<Category> parentCategories = allCategories.Where(c => c.ParentId == null)
   .OrderBy(c => c.Title);

foreach(var cat in parentCategories)
{
    //add the parent category to the item list
    items.Add(new CategoryViewModelItem { Value = cat.Id, Text = cat.Title });
    //now get all its children (separate function in case you need recursion)
    GetSubTree(allCategories, cat, items);
}

private void GetSubTree(IList<Category> allCats, Category parent, IList<CategoryViewModelItem> items)
{
    var subCats = allCats.Where(c => c.ParentId == parentId);
    foreach(var cat in subCats)
    {
        //add this category
        items.Add(new CategoryViewModelItem { Value = cat.Id, Text = parent.Title + " >> " + cat.Title });
        //recursive call in case your have a hierarchy more than 1 level deep
        GetSubTree(allCats, cat, items);
    }
}

Then to render your SelectList, you could send the SelectList as your model (or part of it) for your view:

//in your controller's action
SelectList select = new SelectList(items, "Value", "Text");
return View(select);

And use that in your View:

@Html.DropDownList("Categories", @Model)

Upvotes: 3

Related Questions