I have a simple Category
class to create a self referencing table.
public class Category
{
public int CategoryId{get; set;}
public string Name {get;set;
public int? ParentId {get;set}
public virtual Category Parent {get;set}
public virtual ICollection<Category> Children {get;set;}
}
And a create view generated by EF has the out-of the box area for new category name:
@Html.LabelFor(model => model.Name, new {@class = "control-label"})
@Html.EditorFor(model => model.Name,"", new{@class="form-control"}
and an area that pre-populates the parent category selection
@Html.LabelFor(model => model.ParentId, "Parent Category", new {@class = "control-label"})
@Html.DropdownList("ParentId", null, new {@class ="form-control})
This allows for categories with a number of nested subcategories and additional subcategories nested under other subcategories, etc... etc...
The create view allows you to create a new category and assign a parent category using an @Html.DropdownList
that pulls the text values of all categories but lists only the actual category or subcategory name.
Is there a way to change the display values in the @Html.DropdownList
to display the hierarchical tree instead of a the single parent value?
So instead of the @Html.Dropdownlist
displaying "AAA Batteries" (the value of the new category's parent category) it shows the full hierarchical value of the parent category:
Electronic Supplies >> Batteries >> AAA Batteries
This is of course is a category named "Electronic Supplies" with a subcategory of "Batteries" and a subcategory under that of "AAA Batteries".
You need a method in your model that generates this name for you. Something like:
public class Category
{
public int CategoryId {get; set;}
public int ParentId {get; set;}
public string Name {get; set;}
public string GetFullCategoryName()
{
string result = this.Name;
// note: I removed the argument because it's class member.
Category parent = this.GetParent(); // null for top level Categories
while (parent != null)
{
result = parent.Name + " >> " + result;
parent = GetParent(parent.ParentId);
}
return result;
}
public Category GetParent()
{
// note: I just made this up, you would use whatever EF method you have...
return EF.GetEntity<Category>(this.ParentId);
}
}
Of course you also need a GetParent method...
Edit:
Here's an example to use this (making the assumption that there's a model with a CategoryId property, and a GetAllCategories method):
@Html.DropDownListFor(x => x.CategoryId, Model.GetAllCategories().Select(c => new SelectListItem() { Text = c.GetFullCategoryName(), Value = c.CategoryId }))
Edit 2: I changed the code above to show the entire class, maybe that will make more sense?