How to implement multiple dropdown lists in MVC

12,781

Solution 1

I ended up using the EditorTemplate functionality in order to solve / render this.

The Model changed from this:

public class ValueModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

To this:

public class ValueModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public List<ValueDropDownModel> DropDown { get; set; }
}

public class ValueDropDownModel
{
    [Range(0, 15)]
    public int DropDown { get; set; }

    public int Id { get; set; }
    public string Name { get; set; }

    public List<SelectListItem> AvailableDropDown { get; set; }
}

Within the Views under the folder for Value, there is now a sub folder called EditorTemplates. This contains 2 Views. A ValueModel.cshtml and a ValueDropDownModel.cshtml.

ValueModel.cshtml contains:

@model SomeSolution.Web.Models.ValueModel

<div class="row-fluid">

    <div class="span6">
        <div class="control-group">
            @Html.LabelFor(m => m.Name)
            <div class="controls">
                @Html.EditorFor(m => m.Name)
                @Html.ValidationMessageFor(m => m.Name)
            </div>
        </div>

    </div>
</div>

<div class="row-fluid">
    <div class="span4">
        @for (int i = 0; i < 5; ++i)
        {
            @Html.EditorFor(m => m.DropDown[i])
        }
    </div>

    <div class="span4">
        @for (int i = 5; i < 10; ++i)
        {
            @Html.EditorFor(m => m.DropDown[i])
        }
    </div>

    <div class="span4">
        @for (int i = 10; i < 15; ++i)
        {
            @Html.EditorFor(m => m.DropDown[i])
        }
    </div>
</div>

ValueDropDownModel.cshtml contains:

@model SomeSolution.Web.Models.ValueDropDownModel

<div class="control-group">
    @Html.HiddenFor(m => m.DropDown)
    @String.Format("DropDown {0}", Model.DropDown)
    <div class="controls">
        @Html.DropDownListFor(m => m.Id, Model.AvailableDropDown)
        @Html.ValidationMessageFor(m => m.Id)
    </div>
</div>

The ValueController now includes some helper methods to populate the drop downs

    private void FillAvailableValues(ValueModel modelValue, Entities db)
    {
        var values = (from v in db.Values
                       orderby v.Name
                       select v);

        foreach (var model in modelValue.Values)
        {
            model.AvailableDropDown = new List<SelectListItem>();
            model.AvailableDropDown.Add(new SelectListItem()
            {
                Text = "Unassigned",
                Value = "0",
                Selected = (model.Id == 0)
            });

            foreach (var value in values)
            {
                model.AvailableDropDown.Add(new SelectListItem()
                {
                    Text = value.Name,
                    Value = value.Id,
                    Selected = (model.Id.ToString() == colour.Id)
                });
            }
        }
    }

    private void InitDefaultDropDown(ValueModel model)
    {
        model.DropDown = new List<ValueDropDownModel>();
        for (int i = 0; i < 15; i++)
        {
            model.DropDown.Add(new ValueDropDownModel()
            {
                DropDown = i + 1,
                Id = 0
            });
        }
    }

The FillAvailableValues method is called on the Create ActionResult as well as the Edit ActionResult to initialize the Drop Downs. The InitDefaultDropDown method is called on the Create ActionResult to setup the Drop Downs on the page.

Solution 2

You can re-use the select list - just use the proper overlad of DropDownList or DropDownListFor. What you should (normally) do is give the dropdowns different names. For example:

 @Html.DropDownListFor( m => m.PickedValue1, ViewBag.Values)
 @Html.DropDownListFor( m => m.PickedValue2, ViewBag.Values)

Or, if you prefer the non-strongly typed DropDownList:

 @Html.DropDownList( "PickedValue1", ViewBag.Values)
 @Html.DropDownList( "PickedValue2", ViewBag.Values)
Share:
12,781
iamchrisfryer
Author by

iamchrisfryer

Programming: HTML, JavaScript, CSS, Java/JSP, XML, C#, PHP, jQuery Database: SQL Server 2000, T-SQL, SQL Server 2005, SQL Server Analysis Services, SQL Server 2008, SQL Azure, MySql Methodologies: SDLC, n-tier architecture, Object Oriented Design, Agile Development/XP/TDD, MVC3, MVC4, MVC5, Entity Framework 4.0 Applications: VS 2005/2008/2010/2012, Java NetBeans 3.6, Facebook, Twitter, MS Office XP/2003/2007/2010, JIRA, Subversion (SVN), CruiseControl, MS SharePoint, MercurialHg, Git, Perforce, SourceTree

Updated on June 07, 2022

Comments

  • iamchrisfryer
    iamchrisfryer about 2 years

    Let's say I want to show multiple Drop Down Boxes each with the same values within them within a View using the @Html.DropDownList. Is there an easy way to be able to render all of these Drop Down Boxes without having to bind something like the ViewBag to each of the months returned?

    For example:

    Controller

    List<SelectListItem> items = new List<SelectListItem>();
    
    var values = (from v in db.Values select v);
    
    foreach (var value in values)
    {
        items.Add(new SelectListItem { Text = value.Name, Value = value.Id });
    }
    
    ViewBag.Values = PopulateSelectList("Values");
    

    View

    @Html.DropDownList("Values")
    

    But what the goal would be is to have something like

    <div class="control-group">
        @Html.LabelFor(model => model.DesignStyle)
        <div class="controls">
            @Html.DropDownList("Values")    @Html.DropDownList("Values")
            @Html.DropDownList("Values")    @Html.DropDownList("Values")
            @Html.DropDownList("Values")    @Html.DropDownList("Values")
            @Html.DropDownList("Values")    @Html.DropDownList("Values")
            @Html.DropDownList("Values")    @Html.DropDownList("Values")
        </div>
    </div>
    

    My guess is I would need some sort of @foreach (item in Model) to populate each of the DropDowns on the View

    Here is a sample of my initial thought on how to get something going.

    List<SelectListItem> results = new List<SelectListItem>();
    SelectListItem item = null;
    
    var values = (from v in db.Values select v);
    
    for (int i = 0; i <= 15; i++)
    {
         item = new SelectListItem();
    
         item.Text = "Select a value";
         item.Value = "1";
    
         results.Add(item);
    
         foreach (var thread in threads)
         {
             item.Text = thread.Name;
             item.Value = thread.Id;
    
             results.Add(item);
         }
     }
    

    What I don't want to do is duplicate the logic to populate a SelectListItem multiple times and put each of those in a separate ViewBag item.