Unobtrusive dropdown validation in MVC 3
So the link below outlines a problem with MVC 3 / unobtrusive validation with dropdown 开发者_如何学Golists. Essentially client side validation script is not emitted for dropdown lists. Is there a straightforward workaround for this? I'm confused as to how MVC 3 was released like this when this bug was reported well before the final release. Is there a simple solution to this that's surfaced while we wait for a fix?
Maybe I'm alone on this, but it seems validating ALL elements of a form is important. :)
DropDownListFor() Unobtrusive Validation Problem
I realize this question is already answered, but I was beating my head against a wall dealing with this very issue for the past day trying to figure out why the example above works fine but my code didn't.
It turns out that if you try to put the select list into your ViewData or ViewBag using the same name as the property being set, then client-side validation won't work. The drop-down will populate, though, so it's highly nonintuitive.
// Do NOT do this:
// In the controller:
ViewBag.ItemID = Database.Items.Select(i => new SelectListItem(){Value = i.ID, Text = i.Name});
// In the view:
@Html.DropDownList("ItemID")
// Instead DO this
// In the controller:
ViewBag.ItemIDList = Database.Items.Select(i => new SelectListItem(){Value = i.ID, Text = i.Name});
// In the view:
@Html.DropDownListFor(m => m.ItemID, (IEnumerable<SelectListItem>)ViewBag.ItemIDList)
While the former yields a perfectly functional drop-down, it somehow just doesn't get client-side validation. If you inspect the HTML, all the attributes on the 'select' element just aren't there.
This is completely opposed to the way every other field or editor populates in MVC, since you can set defaults and current values by setting ViewBag.ItemName = "Bob" and if you have a "ItemName" textbox it will populate with "Bob".
Hopefully me posting this will save someone the same hours-long headache.
You can attach the required data-* attributes to the element so they get picked up by the unobtrusive validation script.
@Html.DropDownListFor(x => x.People, new SelectList(Model.People,"Id", "Name"), "Select Person", new Dictionary<string, object>() {{ "data-val", "true" }, { "data-val-required", "Please select a person" }} )
It also seems to work fine for me
<p>
<p>
<span class="lbl"> @Html.LabelFor(x => x.SelectedTimeZone, " Select a TimeZone: ")</span>
<span>@Html.DropDownListFor(x => x.SelectedTimeZone, Model.TimeZones)</span>
<span class="validation-error">@Html.ValidationMessageFor(x => x.SelectedTimeZone)</span>
</p>
// view model
[Required(ErrorMessage = "Time zone is required")]
public string SelectedTimeZone { get; set; }
public SelectList TimeZones { get; set; }
public SetupViewModel()
{
TimeZones = new SelectList(TimeZoneExtensions.BuildTimeZoneList(), "value", "text", "selected");
SelectedTimeZone = "UTC";
}
Ah, that's strange coz the following works perfectly fine for me.
View model:
public class MyViewModel
{
[Required]
public string SelectedItem { get; set; }
public IEnumerable<SelectListItem> Items
{
get
{
return Enumerable.Range(1, 5).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = "item " + x
});
}
}
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View:
@using AppName.Models
@model MyViewModel
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
@Html.DropDownListFor(
x => x.SelectedItem,
new SelectList(Model.Items, "Value", "Text"),
"-- please select an item --"
)
@Html.ValidationMessageFor(x => x.SelectedItem)
<input type="submit" value="OK" />
}
Leave the dropdown without selecting a value and the client side validation will trigger immediately.
精彩评论