Reputation: 1091
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
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