简体   繁体   中英

@Html.DropdownList to show Category >> Subcategory >> Subcategory as text value

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM