2011-01-25 19 views
7

Tengo una lista desplegable simple, el primer elemento de la lista tiene un valor vacío. Si no selecciono nada en la lista, la validación del cliente lo ignora. Tengo ese campo configurado como se requiere en el modelo usando atributos de anotación.La validación no intrusiva del cliente ASP.Net MVC 3 no funciona con las listas desplegables

@Html.DropDownListFor(model => Model.CCPayment.State, UnitedStatesStates.StateSelectList) 



[Required(ErrorMessage = "State is Required.")] 
    public string State 
    { 
     get 
     { 
      return _state; 
     } 
     set 
     { 
      _state = value; 
     } 
    } 

¿Alguna idea? ¿Me estoy perdiendo de algo?

+0

Agregue casillas de verificación a eso también, tengo una casilla de verificación requerida que no se enciende como un campo de error cuando no está marcada. – JBeckton

+0

Realmente no es una respuesta, es más una solución alternativa, pero ¿ha intentado utilizar la interfaz IValidatableObject? ¿Podría ayudarlo por ahora? – RichardW1001

+3

Ya estoy usando IValidatableObject para la validación del lado del servidor. Este es un problema del lado del cliente. Encontré un problema abierto en Codeplex para este http://aspnet.codeplex.com/workitem/7629 – JBeckton

Respuesta

4

Proporcionó muy poca información para que podamos identificar el problema. Es posible que se haya olvidado de incluir los scripts de validación discretos adecuados dentro de su vista, pero ¿quién sabe? No has mostrado tu punto de vista.

Aquí está un ejemplo de trabajo completo:

Modelo:

public class MyViewModel 
{ 
    [Required(ErrorMessage = "State is Required.")] 
    public string State { get; set; } 

    public IEnumerable<SelectListItem> States 
    { 
     get 
     { 
      return Enumerable.Range(1, 5).Select(x => new SelectListItem 
      { 
       Value = x.ToString(), 
       Text = "state " + x 
      }); 
     } 
    } 
} 

controlador:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(new MyViewModel()); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     return View(model); 
    } 
} 

Vista:

@model AppName.Models.MyViewModel 
@{ 
    ViewBag.Title = "Home Page"; 
} 
<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.LabelFor(x => x.State) 
    @Html.DropDownListFor(
     x => x.State, 
     new SelectList(Model.States, "Value", "Text"), 
     "-- Please select a state --" 
    ) 
    @Html.ValidationMessageFor(x => x.State) 
    <input type="submit" value="OK" /> 
} 

Aviso cómo nos están proporcionando un valor predeterminado en el DropDownListFor helper como último parámetro. Eso insertará una opción al principio con un valor vacío y texto personalizado y si el usuario no elige un estado, el validador necesario debería activarse.

+0

debería activarse pero no funciona, traté de agregar el valor predeterminado, pero tengo el mismo problema. La única forma en que puedo hacer que esto funcione es agregar 'required' al atributo de la clase html. El problema es que solo proporciona un mensaje de error genérico en lugar del que especifiqué en el atributo de validación de mi modelo. – JBeckton

+0

También está reventado. Si excluyo jq.validate.js y solo incluyo jq.validate.unobtrusive.js, funciona, lo cual es extraño. –

2

Agregué @ class = "required" a los atributos como dijo un tipo. en el hilo en CodePlex http://aspnet.codeplex.com/workitem/7629 y funcionó bien para mí =)

+0

sí, esto es una solución alternativa pero se obtiene el mensaje de error genérico en lugar del personalizado definido en su atributo de validación. – JBeckton

8

parece un error legítimo, aquí es la mejor solución que he encontrado en mi búsqueda:

http://forums.asp.net/t/1649193.aspx

en resumen. Se coloca la fuente del problema, DropDownListFor, en una extensión de HTML personalizado y recuperar manualmente las reglas de validación clientside discretos como este:

IDictionary<string, object> validationAttributes = htmlHelper. 
    GetUnobtrusiveValidationAttributes(
     ExpressionHelper.GetExpressionText(expression), 
     metadata 
    ); 

Luego se combina su diccionario validationAttributes con cualquier otro atributo html pasado a su ayudante personalizada y se pasa junto al que DropDownListFor

El código completo que estoy usando (tengo una etiqueta en allí también, puede sentirse libre para desacoplar):

public static IHtmlString DropDownListWithLabelFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string label, IEnumerable<SelectListItem> items, string blankOption, object htmlAttributes = null) 
{ 
    var l = new TagBuilder("label"); 
    var br = new TagBuilder("br"); 

    var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData); 
    var mergedAttributes = helper.GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata); 

    if (htmlAttributes != null) 
    { 
     foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(htmlAttributes)) 
     { 
      object value = descriptor.GetValue(htmlAttributes); 
      mergedAttributes.Add(descriptor.Name, value); 
     } 
    } 

    l.InnerHtml = label + br.ToString(TagRenderMode.SelfClosing) + helper.DropDownListFor(expression, items, blankOption, mergedAttributes); 
    return MvcHtmlString.Create(l.ToString(TagRenderMode.Normal)); 
} 
+0

Más allá de mí, ¿cómo esta no es la respuesta aceptada? +1 –

+0

En serio esta es definitivamente la respuesta! ¡Estaba trabajando en esto por tres días! Nunca hubiera imaginado esto. ¡¡¡Increíble!!! Gracias @Milimetric – Rich

+0

¡Esto me SALVÓ después de horas de llegar a ninguna parte! ¡Debe marcarse como la respuesta! – Nick

1

Esta es la manera más simple que encontré para hacerlo, simplemente agregando atributos data-val-*-* en HtmlAttributes de DropDownListFor, dentro de la vista. El siguiente método funciona con RemoteValidation también, si usted no necesita la validación remoto, basta con quitar los elementos que contienen data-val-remote-*:

 @Html.DropDownListFor(m => m.yourlistID, (IEnumerable<SelectListItem>)ViewBag.YourListID, String.Empty, 
     new Dictionary<string, object>() { { "data-val", "true" }, 
     { "data-val-remote-url", "/Validation/yourremoteval" }, 
     { "data-val-remote-type", "POST" }, { "data-val-remote-additionalfield", "youradditionalfieldtovalidate" } }) 

espero que pueda ayudar. ¡Atentamente!

Cuestiones relacionadas