DropDownListFor Unobtrusive Validation Required Not getting correct attributes

This Question is similar but the accepted answer solves it server side, I'm interested in client side solutions.

Given this ViewModel

public class MyViewModel
{
    public string ID { get; set; }

    [Required(ErrorMessage = "I DEMAND YOU MAKE A CHOICE!")]
    [Display(Name = "Some Choice")]
    public int SomeChoice{ get; set; }   
    [Required(ErrorMessage = "I DEMAND YOU MAKE A CHOICE!")]
    [Display(Name = "Keyword")]
    public string Keyword { get; set; }    
}

and the razor

<div>
@Html.LabelFor(model => model.SomeChoice, new { @class = "label" })
@Html.DropDownListFor(model => model.SomeChoice, (SelectList)ViewBag.SomeChoice, "Select...")
@Html.ValidationMessageFor(model => model.SomeChoice)
</div>

and assume ViewBag.SomeChoice contains a select list of choices

The rendered html doesn't get the data-val="true" data-val-required="I DEMAND YOU MAKE A CHOICE!" attributes in it like @Html.EditorFor(model => model.Keyword) or @Html.TextBoxFor would render.

WHY?

Adding a class = "required" to it like so

@Html.DropDownListFor(model => model.SomeChoice, (SelectList)ViewBag.SomeChoice, "Select...", new { @class = "required" })

which uses the jQuery Validation class semantics and blocks on submit but doesn't display the message. I can do this kind of thing

@Html.DropDownListFor(model => model.SomeChoice, (SelectList)ViewBag.SomeChoice, "Select...", new Dictionary<string, object> { { "data-val", "true" }, { "data-val-required", "I DEMAND YOU MAKE A CHOICE!" } })

Which will put the right attributes there, and blocks on submit and shows the message but doesn't take advantage of the RequiredAttribute ErrorMessage I have on my ViewModel

So has anyone written a DropDownListFor that behaves like the other HtmlHelpers with regard to Validation?

EDIT Here is my EXACT code

In HomeController.cs

  public class MyViewModel
  {
    [Required(ErrorMessage = "I DEMAND YOU MAKE A CHOICE!")]
    [Display(Name = "Some Choice")]
    public int? SomeChoice { get; set; }
  }


    public ActionResult About()
    {
        var items = new[] { new SelectListItem { Text = "A", Value = "1" }, new SelectListItem { Text = "B", Value = "2" }, new SelectListItem { Text = "C", Value = "3" }, };
        ViewBag.SomeChoice = new SelectList(items,"Value", "Text");
        ViewData.Model = new MyViewModel {};
        return View();
    }

About.cshtml

@using Arc.Portal.Web.Host.Controllers
@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())
{
<div>
    @Html.LabelFor(model => model.SomeChoice)
    @Html.DropDownListFor(model => model.SomeChoice, (SelectList)ViewBag.SomeChoice, "Select...")
    @Html.ValidationMessageFor(model => model.SomeChoice)
</div>

<button type="submit">OK</button>
}

And here is the rendered code

<form action="/Home/About" method="post">    <div>
    <label for="SomeChoice">Some Choice</label>
    <select id="SomeChoice" name="SomeChoice"><option value="">Select...</option>
<option value="1">A</option>
<option value="2">B</option>
<option value="3">C</option>
</select>
    <span class="field-validation-valid" data-valmsg-for="SomeChoice" data-valmsg-replace="true">    </span>
</div>
<button type="submit">OK</button>
</form>

It posts back to my controller...this shouldn't happen


Simply use a nullable integer on the property you are binding the dropdownlist to on your view model:

[Required(ErrorMessage = "I DEMAND YOU MAKE A CHOICE!")]
[Display(Name = "Some Choice")]
public int? SomeChoice { get; set; }  

Also in order to get proper unobtrusive HTML5 data-* attributes the dropdown must be inside a form:

@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())
{
    <div>
        @Html.LabelFor(model => model.SomeChoice, new { @class = "label" })
        @Html.DropDownListFor(
            model => model.SomeChoice, 
            Model.ListOfChoices, 
            "Select..."
        )
        @Html.ValidationMessageFor(model => model.SomeChoice)
    </div>

    <button type="submit">OK</button>
}

Also you will notice that I got rid of ViewBag (which I simply cannot stand) and replaced it with a corresponding property on your view model which will contain the possible choices for the dropdown.


I had the same problem. And noticed that this happens when dropDownList is populated from ViewBag or ViewData. If you would write @Html.DropDownListFor(model => model.SomeChoice, Model.SomeChoice, "Select...") as in above example validation attributes would be wrote.


Those who are here looking for the same behavior in Kendo dropdownlist, please add 'required' in your code.

@(Html.Kendo().DropDownListFor(m => m)
    .Name("FeatureId").BindTo((System.Collections.IEnumerable)ViewData[CompanyViewDataKey.Features])
    .DataValueField("Id")
    .DataTextField("Name")
    .OptionLabel("--Select--")
    .HtmlAttributes(new { title="Select Feature", required="required"})

)

[Required] attribute in the viewmodel did not work for me but adding the above in Htmlattributes did. Hope this helps someone.

链接地址: http://www.djcxy.com/p/56608.html

上一篇: 在ViewModel上进行表单验证

下一篇: DropDownListFor Unobtrusive验证必需没有得到正确的属性