8

¿Qué enfoque recomienda para validar un DateTime en el lado del cliente en MVC?MVC2 Validación del lado del cliente para un DateTime?

Digamos que tengo un modelo con una propiedad llamada DateOfBirth que es DateTime, como tal.

public class UserModel 
{ 
    [DataType(DataType.Date)] 
    public DateTime DateOfBirth {get;set;} 
} 

En la vista, que tienen un simple

<%: Html.LabelFor(model=>model.DateOfBirth) %> 
<%: Html.EditorFor(model=>model.DateOfBirth) %> 
<%: Html.ValidationMessageFor(model=>model.DateOfBirth) %> 
<input type="submit" value="Submit" /> 

que puede utilizar cualquiera de las validaciones Microsoft MVC o las validaciones de jQuery. ¿Cómo obtengo el DateTime para validar el lado del cliente?

Me doy cuenta de que todo lo que DataTypeAttribute hace es proporcionar sugerencias de formato y no hace ninguna validación (deja esa parte en ModelBinder).

Básicamente quiero duplicar lo que hace el ModelBinder cuando intenta poner el valor contabilizado en la propiedad DateOfBirth del modelo.

¿Cuáles son sus recomendaciones?

+0

preventivamente: Sí, lo he visto, leído, y me encantó la publicación de Phil Haack sobre validación personalizada. http: // haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx – Josh

Respuesta

4

como se sugirió anteriormente, siga el post de Phil Haack en validaciones personalizadas: http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx

He aquí cómo lo haría:


  1. Añadir una clase "DateFormatAttribute", así:

    public class DateFormatAttribute : ValidationAttribute { 
     public override bool IsValid(object value) {  
     if (value == null) { 
      return true; 
     } 

     // Note: the actual server side validation still has to be implemented :-) 
     // Just returning true now... 

     return true; 
     } 
    } 

  1. Añadir una clase "DateFormatValidator", así:

    public class DateFormatValidator : DataAnnotationsModelValidator 
    { 
     string message; 

     public PriceValidator(ModelMetadata metadata, ControllerContext context 
     , DateFormatAttribute attribute) 
     : base(metadata, context, attribute) 
     { 
     message = attribute.ErrorMessage; 
     } 

     public override IEnumerable GetClientValidationRules() 
     { 
     var rule = new ModelClientValidationRule { 
      ErrorMessage = message, 
      ValidationType = "date" // note that this string will link to the JavaScript function we'll write later on 
     }; 

     return new[] { rule }; 
     } 
    } 

  1. Register las clases anteriores en algún lugar de Global. asax.cs:

    DataAnnotationsModelValidatorProvider 
     .RegisterAdapter(typeof(DateFormatAttribute), typeof(DateFormatValidator)); 

  1. A dd una función de validación en el cliente. Tenga en cuenta que esto tendrá que implementarse atribuyendo la configuración regional del usuario. El siguiente es un holandés (nl-NL, NL-BE) función de validación del lado del cliente:

    /* 
    * Localized default methods for the jQuery validation plugin. 
    * Locale: NL 
    */ 
    jQuery.extend(jQuery.validator.methods, { 
     date: function(value, element) { 
      return this.optional(element) || /^\d\d?[\.\/-]\d\d?[\.\/-]\d\d\d?\d?$/.test(value); 
     } 
    }); 

Eso debe cubrir cosas ...

+0

+1 explicación bastante buena y completa –

+0

No he intentado esto todavía, pero se ve bien. Pregunta: Dado que el nuevo atributo no agrega nada que el atributo DataType (DataType.Date) no haga en el lado del servidor, ¿es posible ampliar ese atributo? – Josh

+0

No lo he intentado, pero puede funcionar ... – maartenba

0

Estoy en contra del mismo problema y no puedo encontrar una solución. No puedo creer que todos no se hayan encontrado con este problema. Estaba usando el módulo jquery.maskedinput.js y funcionó muy bien, pero cuando comencé a agregar la decoración "[DataType (DataType.Date)]" con "EditorFor" si asigna la entrada de fecha y hora una clase de clase = "cuadro de texto linea sola". Al agregar esta clase, se rompe la entrada enmascarada js. También formatea mis fechas más bajas como "2/3/1010", que luego hace sonar mi máscara jquery de "99/99/9999".

1

Josh,

su problema es bastante un problema común en MVC, que es que el modelbinder está tratando de enlazar los valores introducidos desde la forma en el modelo. obviamente, si no se ajusta, obtendrá un error inmediatamente.

entonces, ¿cómo hago que el encuadernador use mi validación personalizada? y devolver mi mensaje de error?

Bueno, primero lea y haga las cosas escritas por phil hack. entonces tienes tu validación personalizada.

lo siguiente es. ¡no use enteros ni fechas en su modelo! Si el usuario puede ingresar lo que quiera en un cuadro de texto, esto siempre dará problemas.

lo que debe hacer es crear un objeto plano de su objeto.

un flatObject es bastante simple. Es un objeto, una copia exacta de las variables en el interior, solamente, el inst y datetimes son cadenas (cos los que se unen siempre en el modelbinder)

ejemplo:

namespace MVC2_NASTEST.Models { 

    public partial class FlatNieuw { 
     public int Niw_ID { get; set; } 
     public string Niw_Datum { get; set; } 
     public string Niw_Titel { get; set; } 
     public string Niw_Bericht { get; set; } 
     public int Niw_Schooljaar { get; set; } 
     public bool Niw_Publiceren { get; set; } 
    } 
} 

los únicos enteros que tengo son de la desplegables, porque aquellos no fallan, si el valor en los desplegables son enteros. la fecha (datum) es una cadena. hago la validación personalizada en esta cadena. el modelbinder se une a este objeto FlatNieuw.

mi clase Nieuw tiene exactamente los mismos nombres de campo que esta clase. entonces cuando estás usando UpdateModel() esto todavía funciona. si está haciendo una nueva entrada, puede usar automapper para asignar este objeto plano a su Objeto normal.

Creo que esto, junto con el blog phil hack debe darte una mano sobre cómo hacer esto. si tiene preguntas, no dude en preguntar.

0

De acuerdo con mi experiencia, algunas veces las validaciones de Microsoft MVC o las validaciones de jQuery son una muerte excesiva para algunos proyectos que estamos desarrollando. Es por eso que algunas veces codifico/agarro pequeños por mi cuenta.

Solución uno: complemento personalizada (se puede cambiar en la forma en que más le convenga)

(function($) { 
    $.fn.extend({ 
      ValidateInput: function() { 
       var bValid = true; 
       this.removeClass('ui-state-error'); 
       this.each(function() { 
        if ($(this).hasClass('date')) { 

          var valdate = checkRegexp($(this), /^(([0-2]\d|[3][0-1])\/([0]\d|[1][0-2])\/[1-2]\d{3})$/, "date format is wrong, please input as dd/MM/yyyy, e.g. 02/28/2010"); 
          if (!valdate) { 
           $(this).val("input in 'dd/mm/yyyy' format"); 
          } 
          bValid = bValid && valdate; 
       return bValid; 

         } 
       }); 

    }}); 

    function checkRegexp(o, regexp, n) { 
     if (!(regexp.test(o.val()))) { 
      o.addClass('ui-state-error'); 
      //updateTips(n); 
      return false; 
     } else { 
      return true; 
     } 
     } 

})(jQuery); 

en su vista:

  1. Agregar clase = 'fecha' a la entrada cuadro
  2. llamar al plugin $("#yourInput").alidateInput();

Solución 2: Uso jQuery UI fecha de recogida (la solución que estoy usando ahora)

 <script language="javascript" type="text/javascript"> 
      $(function() { 
// use date picker to your textbox input 
       $(".yourInput").datepicker(); 
       $(".yourInput").datepicker('option', { dateFormat: "dd/mm/yy" }); 
// disable any human input to the textbox input 
       $(".yourInput").keyup(function() { 
        $(this).val(""); 
       }); 
      }); 
     </script> 

Más detalles sobre Solución 2: http://www.gregshackles.com/2010/03/templated-helpers-and-custom-model-binders-in-asp-net-mvc-2/

Cuestiones relacionadas