Reputation: 4718
I have a ViewModel that contains a List of SelectListItems called Types. When I go into the Edit page the types are populated and the dropdownlist contains the items as expected. When I post the changes back the list of SelectListItems is null. i.e. 'model.Types' is null.
Why is this and how do I fix it?
I've seen this question asked a few times but they all have different answer and I've tried a few and they don't work.
I'm new to MVC so please help.
Thanks
My ViewModel:
public class StaticItemViewModel
{
public Static_Item StaticItem { get; set; }
public List<SelectListItem> Types { get; set; }
}
My Controller:
public class StaticItemController : Controller
{
private DB db = new DB();
public ActionResult Edit(int id)
{
Static_Item staticItem = db.Static_Item.Find(id);
if (staticItem == null)
{
return HttpNotFound();
}
StaticItemViewModel staticItemViewModel = new StaticItemViewModel()
{
StaticItem = staticItem,
Types = LoadStaticItemTypes(staticItem.Type)
};
return View(staticItemViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="StaticItem")] StaticItemViewModel model)
{
if (ModelState.IsValid)
{
model.StaticItem.Changed_Date = DateTime.Now;
db.Entry(model.StaticItem).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
List<SelectListItem> LoadStaticItemTypes(string selectedType = "")
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (var item in db.Static_Item.Select(s => s.Type).Distinct().OrderBy(s => s))
{
items.Add(new SelectListItem { Text = item, Value = item, Selected = item == selectedType });
}
return items;
}
}
My View:
@model StaticItemViewModel
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>@Model.StaticItem.Description</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.StaticItem.UN_Static_Item)
<div class="form-group">
@Html.LabelFor(model => model.StaticItem.Description, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.StaticItem.Description, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.StaticItem.Description, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.StaticItem.Type, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.StaticItem.Type, Model.Types, new { @class="form-control" })
@Html.ValidationMessageFor(model => model.StaticItem.Type, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
Upvotes: 1
Views: 1061
Reputation: 239440
That's because Types
just holds the list of options, and the actual options themselves will never be posted back. You need a property like:
public List<int> SelectedTypes { get; set; }
And then bind to that in your view:
@Html.ListBoxFor(m => m.SelectedTypes, Model.Types)
That's assuming your option values are just the type's PK, you could just as well bind to a List<string>
, etc., but it must be a primitive type (string, int, etc.). You can't post back the full Type
objects. If you need those, you'll need to use the list of ids, or whatever, to look them up from the database.
Upvotes: 4