user1469655
user1469655

Reputation: 1091

Values of dropdown lists are not passed back to the controller

I have a view model which consists of a patient object and Visits collection. The view model is populated with all the correct property values and the properties display correctly in the Edit view. I also verified the property values in the view model before the model was passed to the view in the Edit (GET) action of the controller.

The problem is, even if I change none of the properties while in the edit view, the properties bound to dropdown lists (gender and condition) are not passed back to the Edit (POST) action of the controller. This results in an exception being thrown.

The properties have values but somewhere they are getting lost. How do I troubleshoot this?

ASP.NET MVC 4 RC

public ActionResult Edit(int id = 0)
{
    var patient = this.db.Patients.Where(p => p.Id == id).FirstOrDefault();
    var visits = this.db.Visits.Where(v => v.PatientId == patient.Id && v.IsActive).OrderByDescending(v => v.VisitDate);

    PatientEditViewModel model = new PatientEditViewModel();
    model.Patient = patient;
    model.Visits = visits;

    if (patient == null)
    {
        return this.HttpNotFound();
    }

    ViewBag.GenderId = new SelectList(this.db.Genders, "Id", "Name", patient.GenderId);
    ViewBag.HandednessId = new SelectList(this.db.Handednesses, "Id", "Name", patient.HandednessId);

    return this.View(model);
}


[HttpPost]
public ActionResult Edit(PatientEditViewModel model)
{
    Mapper.CreateMap<PatientEditViewModel, Patient>();

    var entity = Mapper.Map<PatientEditViewModel, Patient>(model);

    if (ModelState.IsValid)
    {
        this.db.Entry(entity).State = EntityState.Modified;
        this.db.SaveChanges();
    }

    this.ViewBag.GenderId = new SelectList(this.db.Genders, "Id", "Name", entity.GenderId);
    this.ViewBag.HandednessId = new SelectList(this.db.Handednesses, "Id", "Name", entity.HandednessId);

    return this.View(model);
}

@model Web.Models.PatientEditViewModel

@{
    ViewBag.Title = "XXX";
}


@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Patient</legend>

        @Html.HiddenFor(model => model.Patient.Id)

        <div class="editor-label">
            @Html.LabelFor(model => model.Patient.GenderId, "Gender")
        </div>
        <div class="editor-field">
            @Html.DropDownFor("GenderId", String.Empty)
            @Html.ValidationMessageFor(model => model.Patient.GenderId)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Patient.HandednessId, "Handedness")
        </div>
        <div class="editor-field">
            @Html.DropDownFor("HandednessId", String.Empty)
            @Html.ValidationMessageFor(model => model.Patient.HandednessId)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Patient.Comments)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Patient.Comments)
            @Html.ValidationMessageFor(model => model.Patient.Comments)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

@Html.Partial("_CurrentAndPreviousVisits", Model.Visits)


@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")


}

Upvotes: 2

Views: 5628

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1039170

There is no Html.DropDownFor helper. Maybe you meant Html.DropDownList or Html.DropDownListFor. Personally I would recommend you the second and strongly typed version.

So in your PatientEditViewModel model you define the following properties:

public string GenderId { get; set; }
public IEnumerable<SelectList> Genders { get; set; }

public string HandednessId { get; set; }
public IEnumerable<SelectList> Handednesses { get; set; }

and then in your controller action you forget about ViewBag and properly populate your view model. So you replace the 2 lines of ViewBag with 2 lines of view model assignment:

model.Genders = new SelectList(this.db.Genders, "Id", "Name", patient.GenderId);
model.Handednesses = new SelectList(this.db.Handednesses, "Id", "Name", patient.HandednessId);

and in your view you use the strongly typed versions of the helpers:

@Html.DropDownListFor(x => x.GenderId, Model.Genders)

and:

@Html.DropDownListFor(x => x.HandednessId, Model.Handednesses)

Now inside your POST action you will get the 2 selected values inside the GenderId and HandednessId properties of your view model. Obviously in your POST action if you want to redisplay the same view you remove the 2 lines of ViewCrap (pardon I meant ViewBag) with the 2 lines of view model property assignment.

Upvotes: 4

Related Questions