Good evening everyone I have a question regarding validation of drop-down list values. I have a view that is bound to a view model type called ReservationData.
This object contains a property CustomerVehicles of
type List<VehicleData>. VehicleDatahas
two int properties VehicleMakeId and VehicleModelId.
On my view I am trying to loop over the number of items in the CustomerVehicles collection
and displaying two dropdowns for each, a vehicle make dropdown and a vehicle model dropdown usingDropDownListFor.
When I try to submit and validate I do not see any validation errors displayed on the screen.
Just in case you are wondering I have added a ValidationMessageFor for
each dropdown as well. I am not sure if this is an issue with the structure of my view model and its complexity and how the controls need to be named or how the ids need to be set. Any help would be greatly appreciated.
Here is the code for the looping over the collection:
@for (var i = 0; i < Model.CustomerVehicles.Count(); i++)
{
var vehicleNumber = i + 1;
<div class="vehicle-selection-wrapper">
<div class="content-container">
<h3>
Vehicle @vehicleNumber</h3>
<img class="vehicle-image" alt="manufacturer image" src="@Url.Content("~/Content/images/default-vehicle.gif")" /><br />
@Html.LabelFor(m => m.CustomerVehicles[i].VehicleMakeId)
@Html.DropDownListFor(m => m.CustomerVehicles[i].VehicleMakeId
, new SelectList(Model.VehicleMakes, "Id", "Name")
, @UIDisplay.Dropdown_DefaultOption, new { @class = "long-field" })<br />
@Html.ValidationMessageFor(m => m.CustomerVehicles[i].VehicleMakeId)<br />
@Html.LabelFor(m => m.CustomerVehicles[i].VehicleModelId)
@Html.DropDownListFor(m => m.CustomerVehicles[i].VehicleModelId
, new SelectList(new List<CWR.Domain.VehicleModel>(), "Id", "Name")
, @UIDisplay.Dropdown_DefaultOption, new { @class = "long-field" })
@Html.ValidationMessageFor(m => m.CustomerVehicles[i].VehicleModelId)
</div>
</div>
}
Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
public class VehicleData
{
[Display(Name="VehicleData_VehicleMake", ResourceType=typeof(UIDisplay))]
[Required(ErrorMessageResourceName="VehicleData_VehicleMakeRequired"
, ErrorMessageResourceType=typeof(UIValidation)
, AllowEmptyStrings = false)]
public int VehicleMakeId { get; set; }
[Display(Name = "VehicleData_VehicleModel", ResourceType = typeof(UIDisplay))]
[Required(ErrorMessageResourceName = "VehicleData_VehicleModelRequired"
, ErrorMessageResourceType = typeof(UIValidation)
, AllowEmptyStrings=false)]
public int VehicleModelId { get; set; }
}
Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
Ok so I was testing and noticed that if I keep my code identical except I swap theHtml.DropdownListFor calls
with Html.TextboxFor calls
then the validation works. What could be causing this? Could it be a framework bug with the unobtrusive validation?
Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
Ok so I was testing and noticed that if I keep my code identical except I swap theHtml.DropdownListFor calls
with Html.TextboxFor calls
then the validation works. What could be causing this? Could it be a framework bug with the unobtrusive validation?
Michael,
Yes, this is a bug in unobtrusive validation of dropdownlists. MVC 3 RTM does not create unobtrusive validation for a collection of dropdownlists. See
http://aspnet.codeplex.com/workitem/7629. The problem is that the code to build the unobtrusive validation makes a call WITHOUT reference to the metadata, which causes it to return a null value. The solution
is to build your own HtmlHelper for DropDownListFor (I call mine DdUovFor), and in the helper, make the following call:
Then, you can combine the IDictionary with any other htmlAttributes, and pass the result to SelectExtensions.DropDownListFor(), and you will receive back a dropdownlist with the unobtrusive validation rules.
counsellorben
Marked as answer by mreyeros on Feb 04, 2011 01:51 AM
Good afternoon counsellorben could you please provide me with a sample of how your helper is defined. It would be greatly appreciated.
Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
Thank you very much counsellorben I will try to add this to my project and see how it works. If you notice there was a piece of the code that was blocked. Could you please forward me the code sample to my email mreyerosATgmail.com.
Thank you again.
Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
mreyeros
Contributor
4022 Points
736 Posts
MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 02:19 AM|LINK
Good evening everyone I have a question regarding validation of drop-down list values. I have a view that is bound to a view model type called
ReservationData.This object contains a property
CustomerVehiclesof typeList<VehicleData>.VehicleDatahas twointpropertiesVehicleMakeIdandVehicleModelId.On my view I am trying to loop over the number of items in the
CustomerVehiclescollection and displaying two dropdowns for each, a vehicle make dropdown and a vehicle model dropdown usingDropDownListFor.When I try to submit and validate I do not see any validation errors displayed on the screen.
Just in case you are wondering I have added a
ValidationMessageForfor each dropdown as well. I am not sure if this is an issue with the structure of my view model and its complexity and how the controls need to be named or how the ids need to be set. Any help would be greatly appreciated.Here is the code for the looping over the collection:
@for (var i = 0; i < Model.CustomerVehicles.Count(); i++) { var vehicleNumber = i + 1; <div class="vehicle-selection-wrapper"> <div class="content-container"> <h3> Vehicle @vehicleNumber</h3> <img class="vehicle-image" alt="manufacturer image" src="@Url.Content("~/Content/images/default-vehicle.gif")" /><br /> @Html.LabelFor(m => m.CustomerVehicles[i].VehicleMakeId) @Html.DropDownListFor(m => m.CustomerVehicles[i].VehicleMakeId , new SelectList(Model.VehicleMakes, "Id", "Name") , @UIDisplay.Dropdown_DefaultOption, new { @class = "long-field" })<br /> @Html.ValidationMessageFor(m => m.CustomerVehicles[i].VehicleMakeId)<br /> @Html.LabelFor(m => m.CustomerVehicles[i].VehicleModelId) @Html.DropDownListFor(m => m.CustomerVehicles[i].VehicleModelId , new SelectList(new List<CWR.Domain.VehicleModel>(), "Id", "Name") , @UIDisplay.Dropdown_DefaultOption, new { @class = "long-field" }) @Html.ValidationMessageFor(m => m.CustomerVehicles[i].VehicleModelId) </div> </div> }raduenuca
All-Star
24675 Points
4250 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 05:16 AM|LINK
Hi,
Can you show the VehicleData model? Do you have any DataAnnotations attribute on those properties (like Required)?
Radu Enuca | Blog
mreyeros
Contributor
4022 Points
736 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 02:14 PM|LINK
public class VehicleData { [Display(Name="VehicleData_VehicleMake", ResourceType=typeof(UIDisplay))] [Required(ErrorMessageResourceName="VehicleData_VehicleMakeRequired" , ErrorMessageResourceType=typeof(UIValidation) , AllowEmptyStrings = false)] public int VehicleMakeId { get; set; } [Display(Name = "VehicleData_VehicleModel", ResourceType = typeof(UIDisplay))] [Required(ErrorMessageResourceName = "VehicleData_VehicleModelRequired" , ErrorMessageResourceType = typeof(UIValidation) , AllowEmptyStrings=false)] public int VehicleModelId { get; set; } }mreyeros
Contributor
4022 Points
736 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 02:31 PM|LINK
UPDATE:
Ok so I was testing and noticed that if I keep my code identical except I swap the
Html.DropdownListForcalls withHtml.TextboxForcalls then the validation works. What could be causing this? Could it be a framework bug with the unobtrusive validation?raduenuca
All-Star
24675 Points
4250 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 02:47 PM|LINK
How is the html for the select (dropdownlist) and textbox (for the m => m.CustomerVehicles[i].VehicleMakeId) generated?
Radu Enuca | Blog
counsellorbe...
Member
540 Points
112 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 03:24 PM|LINK
Michael,
Yes, this is a bug in unobtrusive validation of dropdownlists. MVC 3 RTM does not create unobtrusive validation for a collection of dropdownlists. See http://aspnet.codeplex.com/workitem/7629. The problem is that the code to build the unobtrusive validation makes a call WITHOUT reference to the metadata, which causes it to return a null value. The solution is to build your own HtmlHelper for DropDownListFor (I call mine DdUovFor), and in the helper, make the following call:
IDictionary<string, object> validationAttributes = htmlHelper .GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata);Then, you can combine the IDictionary with any other htmlAttributes, and pass the result to SelectExtensions.DropDownListFor(), and you will receive back a dropdownlist with the unobtrusive validation rules.
counsellorben
mreyeros
Contributor
4022 Points
736 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 04:06 PM|LINK
Good afternoon counsellorben could you please provide me with a sample of how your helper is defined. It would be greatly appreciated.
counsellorbe...
Member
540 Points
112 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 04:47 PM|LINK
Michael,
OK, you asked for it, you got it. Below is the code for my helpers:
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DdUovFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList) { return DdUovFor(htmlHelper, expression, selectList, null /* optionLabel */, null /* htmlAttributes */); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DdUovFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes) { return DdUovFor(htmlHelper, expression, selectList, null /* optionLabel */, new RouteValueDictionary(htmlAttributes)); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DdUovFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, IDictionary<string, object> htmlAttributes) { return DdUovFor(htmlHelper, expression, selectList, null /* optionLabel */, htmlAttributes); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DdUovFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel) { return DdUovFor(htmlHelper, expression, selectList, optionLabel, null /* htmlAttributes */); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DdUovFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes) { return DdUovFor(htmlHelper, expression, selectList, optionLabel, new RouteValueDictionary(htmlAttributes)); } [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Users cannot use anonymous methods with the LambdaExpression type")] [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DdUovFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes) { if (expression == null) { throw new ArgumentNullException("expression"); } ModelMetadata metadata = ModelMetadata.From_L_a_m_b_d_a_E_x_p_r_e_s_s_i_o_n(expression, htmlHelper.ViewData); IDictionary<string, object> validationAttributes = htmlHelper .GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata); if (htmlAttributes == null) htmlAttributes = validationAttributes; else htmlAttributes = htmlAttributes.Concat(validationAttributes).ToDictionary(k => k.Key, v => v.Value); return SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, optionLabel, htmlAttributes); }Also, in the web.config file in the Views folder, be sure to add the namespace which covers your HtmlHelper class, in the following section:
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="YOUR NAMESPACE HERE" />counsellorben
mreyeros
Contributor
4022 Points
736 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 04:53 PM|LINK
Thank you very much counsellorben I will try to add this to my project and see how it works. If you notice there was a piece of the code that was blocked. Could you please forward me the code sample to my email mreyerosATgmail.com.
Thank you again.
counsellorbe...
Member
540 Points
112 Posts
Re: MVC 3 dropdownlist validation not working for complex view model
Feb 03, 2011 04:57 PM|LINK
Michael,
I edited my post, and added underbars to the blocked line. It is now visible, and all you need to do is remove the underbar characters.
counsellorben