user672118
user672118

Reputation:

MVC 3 Drop Down List Not Binding to Model

In my application I have a drop down list to represent different choices. Note that Paragraph is a model and the section is just one field in the model.

@Html.DropDownList("Sections")

And here is my controller.

public ActionResult Edit(int id)
{
    var paragraph = db.Paragraphs.Find(id);

    ViewBag.Sections = new SelectList(
        db.Sections.Select(s => new { s.ID, s.Name }),
        "ID", "Name", paragraph.SectionID
    );

    return View(paragraph);
}

[HttpPost]
public ActionResult Edit(Paragraph paragraph, HttpPostedFileBase document)
{
    if (ModelState.IsValid)
    {
        // Do some stuff.
    }

    ViewBag.Sections = new SelectList(
        db.Sections.Select(s => new { s.ID, s.Name }),
        "ID", "Name", paragraph.SectionID
    );

    return View(paragraph);
}

When I submit the form though the drop down list is not bound to the model. Causing ModelState.IsValid to be false and making my life horrible. Any suggestions?

EDIT: When I submit the form I get the following error:

There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'Sections'.

EDIT: It appears that I only get the preceding error when I try to submit the file.

EDIT: Model

public class Paragraph
{
    public int ID { get; set; }

    [Required]
    public int Major { get; set; }

    [Required]
    public int Minor { get; set; }

    [Required(ErrorMessage = "Name is required")]
    [StringLength(4000)]
    public string Name { get; set; }

    public int SectionID { get; set; }
    public virtual Section Section { get; set; }
}

Form: (It's a lot.)

<form class="form-horizontal" action="/Paragraph/Edit" method="post" enctype="multipart/form-data">
    <fieldset>
        <div class="control-group">
            <label class="control-label" for="section">Section</label>
            <div class="controls">
                @Html.DropDownList("Sections")
            </div>
        </div>
        <div class="control-group">
            <label class="control-label" for="major">Major</label>
            <div class="controls">
                <input type="number" class="input-large" name="major" value="@Model.Major" />
            </div>
        </div>
        <div class="control-group">
            <label class="control-label" for="minor">Minor</label>
            <div class="controls">
                <input type="number" class="input-large" name="minor" value="@Model.Minor" />
            </div>
        </div>
        <div class="control-group">
            <label class="control-label" for="name">Name</label>
            <div class="controls">
                <input type="text" class="input-large" name="name" value="@Model.Name" />
            </div>
        </div>
        <div class="control-group">
            <label class="control-label" for="document">Document</label>
            <div class="controls">
                <input type="file" class="input-file" name="document" />
            </div>
        </div>
        <div class="form-actions">
            <input type="submit" class="btn btn-primary" value="Save" />
            <a class="btn" href="/Paragraph/Show/@Model.ID">Cancel</a>
        </div>
    </fieldset>
</form>

Upvotes: 1

Views: 6446

Answers (5)

Vinicius Sin
Vinicius Sin

Reputation: 1581

Friend had the same problem when doing cascading dropdownlist

And there is no why to bind parent dropdownlist. So what I did was to fill the parent dropdownlist the same way as the soon. Created an action, called it on json and filled it using jquery.

My action on controller:

public ActionResult GetStates()
    {
        if (Request.IsAjaxRequest())
        {
            using (MyModel banco = new myModel())
            {

                return Json(new SelectList(banco.SyStates.ToList(), "StateId", "StateName"), JsonRequestBehavior.AllowGet);

            }
        }
        return View();

    }

The view:

      <select id="StateList" name="StateList"></select> 

<script>

   $(document).ready(function () {



         var URL = "/ControllerName/GetStates";
         $.getJSON(URL, function (data) {



         var items = '<option>Selecione o estado</option>';
         $.each(data, function (i, State) {
             items += "<option value='" + State.Value + "'>" + State.Text + "</option>";
             // state.Value cannot contain ' character. We are OK because state.Value = cnt++;

         });
         $('#StateList').html(items);
         //$('#CitiesTrID').show();

     })

 });

Got cascading example on: http://blogs.msdn.com/b/rickandy/archive/2012/01/09/cascasding-dropdownlist-in-asp-net-mvc.aspx

Upvotes: 0

Andy
Andy

Reputation: 2354

So weird! I used to use

@Html.DropDownList("permissionsID", String.Empty)

and it worked fine - all of a sudden, im receiving the same problem. The ddl is not submitting its selected value on the Create (posted) controller method)

So i used

@Html.DropDownListFor(model => model.permissionID, (IEnumerable<SelectListItem>)ViewBag.permissionsID)

and it worked fine!

However I have older controllers that still work till today using the old method - just its not liking it for my new controllers!

It really defies logic...

Upvotes: 0

user672118
user672118

Reputation:

This is late, but better late than never. When you use one of the helpers provided by HtmlHelper it generates the input name behind the scenes. The generated format for this name is Model.Field. For example, a paragraph with a field called "Name" would become Paragraph.Name.

The definition for DropDownList that accepts one parameter uses the name of the drop-down list as the name of the input though. So, a call to DropDownList("Sections") would create an input with a name of "Sections."

In the end though, I decided to concede to Razor and use the built-in HTML helpers. So my drop-down list code looks like: DropDownListFor(vm => vm.Paragraph.SectionID, Models.Sections).

Upvotes: 0

Robby Shaw
Robby Shaw

Reputation: 4915

Change your HTML code to:

@Html.DropDownListFor(m => m.SectionID, ViewBag.Sections as SelectList)

If you don't have a model for this page, then use the code below:

@Html.DropDownList("Sections", ViewBag.Sections as SelectList)

Upvotes: 1

GraemeMiller
GraemeMiller

Reputation: 12263

Just wondering why you are not using strongly type helpers like Html.TextBoxFor etc? You can pass optional html attributes with them if required

I'd make your dropdownlist

@Html.DropDownListFor(model =>model.SectionID,(IEnumerable<SelectListItem>) ViewBag.Sections) 

Others

@Html.HiddenFor(model =>model.ID)
@Html.TextBoxFor(model =>model.Name)
@Html.TextBoxFor(model =>model.Major)
@Html.TextBoxFor(model =>model.Minor)

File can be <input type="file" class="input-file" name="document" />

That should give you the model to bind to. You will be sure of getting the correct names etc back. Also I am including the ID as part of the form.

Upvotes: 1

Related Questions