0

If I have a ViewModel with the following structure:

public class FormViewModel
{
    public string Name { get; set; }
    public List<OptionGroup> Options { get; set; }
    public string Comments { get; set; }
}

public class OptionGroup
{
    public string OptionType;
    public IEnumerable<SelectListItem> Options { get; set; }
    public string SelectedOption;
}

and I want to post to a Controller Method with a signature like:

    [HttpPost]
    public ActionResult PostForm(FormViewModel model)
    {
        // do stuff
    }

How do I bind the SelectLists in the razor such that the selected values are properly bound when sending back to the server?

My first instinct was to just try:

        foreach (OptionGroup optionGroup in Model.Options)
        {
            <div class="form-group">
                <label>@optionGroup.OptionType</label>
                @Html.DropDownListFor(m => optionGroup.SelectedOption, optionGroup.Options, optionGroup.OptionType, new { @class = "form-control" })
            </div>
        }

But that results in not getting any options returns to the server at all.

Then I found this article by Scott Hanselman:

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

and tried using a for loop instead:

        for (int i = 0; i < Model.Options.Count; i++)
        {
            <div class="form-group">
                <label>@Model.Options[i].OptionType</label>
                @Html.DropDownListFor(m => m.Options[i].SelectedOption, Model.Options[i].Options, Model.Options[i].OptionType, new { @class = "form-control", name = string.Format("model.Options[{0}].SelectedOption", i) })
            </div>
        }

This binds the options list, but fails to populate the selected values. (i.e. I get a list of Options on the server, but all the properties of the options are Null)

All the examples I can find are using a simple enumerable as the whole view model - how do you bind to a list of dropdowns when they are only part of the complete ViewModel?

Any pointers would be great,

Cheers!


EDIT

Related: How Do I Model Bind A List Of 'List<SelectItem>' Using MVC.Net which is sending a key value also

and taking into account Stephen Muecke's answer I have tried:

        for (int i = 0; i < Model.Options.Count; i++)
        {
            <div class="form-group">
                <label>@Model.Options[i].OptionType</label>
                @Html.HiddenFor(m => Model.Options[i].OptionType)
                @Html.DropDownListFor(m => m.Options[i].SelectedOption, Model.Options[i].Options, Model.Options[i].OptionType, new { @class = "form-control" })
            </div>
        }

but still no luck :(

Community
  • 1
  • 1
Kaine
  • 1,285
  • 2
  • 16
  • 30

1 Answers1

1

Remove the following from the method

.. name = string.Format("model.Options[{0}].SelectedOption", i) ..

@Html.DropDownList() method will correctly name the select for you, which will be

<select name="Options[0].SelectedOption" ...>
<select name="Options[1].SelectedOption" ...>
// etc

but you are perpending "model." to it so the names will not match up on postback

Your properties for OptionGroup are also missing accessors

public class OptionGroup
{
  public string OptionType { get; set; } // add get/set
  public IEnumerable<SelectListItem> Options { get; set; }
  public string SelectedOption { get; set; } // add get/set
}