iamchrisfryer
iamchrisfryer

Reputation: 290

How to implement multiple dropdown lists in MVC

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.

Upvotes: 3

Views: 13883

Answers (2)

iamchrisfryer
iamchrisfryer

Reputation: 290

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.

Upvotes: 0

Alex
Alex

Reputation: 7838

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)

Upvotes: 4

Related Questions