I wish to show a DropDownList in a view and therfore include in my model (ExampleAddSetupDto) sent to a view a list of entries to populate the dropdownlist. That works fine, but if I have a validation error and redisplay the view with in incoming model my list is now null.
My Action is given below (note: the problem occurs if ModelState.IsValid fails). Also the Action method second parameter may look odd as I am using Autofac to inject the right service into the method).
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Add(ExampleAddSetupDto add, IServiceAddCommit<IExampleAddSetupDto, IExampleAddCommitDto> service)
{
if (ModelState.IsValid)
{
var response = service.Create(add);
if (response.IsValid)
{
TempData["message"] = "You successfully added a new Example Entry";
return View("AddSuccess", response);
}
//else errors, so copy the errors over to the ModelState
response.CopyErrorsToModelState(ModelState, add);
}
// Some validation error, so redisplay same view
return View(add);
}
My model looks like this:
public class ExampleAddSetupDto : IExampleAddSetupDto
{
[StringLength(50, MinimumLength = 2)]
public string Name { get; set; }
public int Option1Id { get; set; }
public int Option2Id { get; set; }
//-----------------------------
//now the properties for the drop down lists
public IList<Option1> PosibleEntriesForOption1 { get; set; }
public IList<Option2> PosibleEntriesForOption2 { get; set; }
}
My View is:
@model ServiceLayer.Example.DTOs.ExampleAddSetupDto
@{
ViewBag.Title = "Add";
}
<h2>Add</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Add an Example item</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-field">
@Html.Label("Option1")
@Html.DropDownListFor(model => model.Option1Id, new SelectList(Model.PosibleEntriesForOption1, "Option1Id", "OptionText"))
@Html.ValidationMessageFor(model => model.Option1Id)
</div>
<div class="editor-field">
@Html.Label("Option2")
@Html.DropDownListFor(model => model.Option2Id, new SelectList(Model.PosibleEntriesForOption2, "Option2Id", "OptionText"))
@Html.ValidationMessageFor(model => model.Option2Id)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
I understand that I need to return the Model.PosibleEntriesForOption in with the form. I tried using the Html.HiddenFor helper in the view to return the list, i.e.
@Html.HiddenFor(model => model.PosibleEntriesForOption1)
but this throws the error
‘The value ‘System.Collections.Generic.List`1[DataClasses.ExampleClasses.Option1]’ is invalid.’.
Clearly I am missing something here and I would appreciate some advice on how to return the lists so that redisplaying the model won’t cause an error.
If you are forced to persist the entire list between the two requests, for whatever reason, the best way I see to do this would be to use:
to store it, and then:
to retrieve it.
Note that anything stored in TempData will be removed automatically after a single request.