2011-01-14 7 views
5

Estoy diseñando una vista que compara dos cadenas de contraseñas. Las dos propiedades en una de mis modelos son bastante sencillos:Validación del lado del cliente que no se activa para la entrada de datos de la evaluación CompareAttribute

[Required] 
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")] 
    [StringLength(20, MinimumLength = 6)] 
    [DataType(DataType.Password)] 
    [Display(Name = "New Password")] 
    public string NewPassword { get; set; } 

    [Required] 
    [DataType(DataType.Password)] 
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")] 
    [StringLength(20, MinimumLength = 6)] 
    [Display(Name = "Confirm Password")] 
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 
    public string ConfirmPassword { get; set; } 

Aquí está mi código de la vista:

<table class="fieldset center" width="400"> 
    <tbody> 
     <tr> 
      <th width="150"> 
       @Html.LabelFor(m => m.NewPassword) 
      </th> 
      <td> 
       @Html.PasswordFor(m => m.NewPassword, new { @class = "itext3" }) 
       <br /><br />@Html.ValidationMessageFor(m => m.NewPassword) 
      </td> 
     </tr>      
     <tr> 
      <th width="150"> 
       @Html.LabelFor(m => m.ConfirmPassword) 
      </th> 
      <td> 
       @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "itext3" }) 
       <br /><br />@Html.ValidationMessageFor(m => m.ConfirmPassword) 
      </td> 
     </tr> 
    </tbody> 
</table> 

Todos los atributos disparar sus mensajes de validación del lado del cliente durante la prueba, a excepción de la CompareAttribute en ConfirmPassword que no se activa hasta que toco el servidor. Sin embargo, en mi controlador el ModelState.IsValid = falso.

He comparado lo que estoy haciendo con la aplicación MVC predeterminada que funciona correctamente. ¿Alguna sugerencia para solucionar problemas y solucionar esto?

Estoy usando MVC 3 RTM.

Respuesta

4

Eche un vistazo a las etiquetas de scripts en su _Layout.cshtml. Supongo que el problema es probablemente tus referencias jQuery. ¿Comenzó el proyecto MVC 3 desde cero o está usando un proyecto de ejemplo o algo así?

Esto es lo que pasó conmigo; Tenía problemas similares ...

  • que estaba usando un código de ejemplo que apuntaba a ajax.microsoft.com en el src atributos
  • Así, por ejemplo, una de las etiquetas de script veía así: <script src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
  • que quería conseguir un mejor manejo de lo js se ejecuta en el lado del cliente así que lo cambié a esto: <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
  • eso es sólo un ejemplo, creo que había un par de etiquetas de script que he cambiado, así

Entonces, después de cambiar a archivos jQuery servidos internamente funcionó. Volví y miré mi archivo local .validate.js ... y era la versión 1.6. Así es como me di cuenta de que el problema se debía a la versión de jQuery o su compatibilidad con una de las otras js libs de todos modos.

En pocas palabras es que parece que 1.7 no funciona completamente con la lib validate.unobtrusive.js que tuve ... puede haber una versión más nueva que funciona con 1.7 ... como dije, yo estaba retocando con un proyecto de ejemplo, por lo que hay algunas incógnitas allí. Supongo que también podría ser una incompatibilidad con la lib de MvcValidation.js entre ella y una de las otras js libs también?

En cualquier caso, diría que la forma más sencilla de expresar su problema es que lo más probable es que esté haciendo referencia a una mala combinación de js libs. Yo diría que la mejor manera de conseguir una buena combinación de js libs es crear un nuevo Asp.Net MVC 3 Project en Visual Studio y ver qué versiones le da por defecto/con la plantilla del proyecto ... eso está asumiendo que no comenzaste el proyecto desde cero. Si lo INICIÓ desde cero, ¿puede ser que haya cambiado su archivo de diseño para tener malas referencias js o si nada de eso es cierto, entonces supongo que podría ser un problema con las plantillas de proyectos de VisualStudio? ... En realidad, yo diría que es dudoso sin embargo. Dicho todo eso, diría que la causa más probable [que apostaría de todos modos] es que acaba de meterse en problemas como yo tratando de usar rápidamente algún código de ejemplo =)

+0

Eso fue todo. En realidad resolvió dos problemas que estaba teniendo. http://stackoverflow.com/questions/4752877/remote-validation-in-asp-net-mvc-3-how-to-use-additionalfields-in-action-method Si vas allí y añades una respuesta apuntando a esta pregunta, te daré la respuesta allí también. ¡GRACIAS! – beaudetious

1

He probado esto con ASP.NET MVC 3 RTM y funcionó bien para mí:

Modelo:

public class MyViewModel 
{ 
    [Required] 
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")] 
    [StringLength(20, MinimumLength = 6)] 
    [DataType(DataType.Password)] 
    [Display(Name = "New Password")] 
    public string NewPassword { get; set; } 

    [Required] 
    [DataType(DataType.Password)] 
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")] 
    [StringLength(20, MinimumLength = 6)] 
    [Display(Name = "Confirm Password")] 
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 
    public string ConfirmPassword { get; set; } 
} 

controlador:

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

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

Vista:

@model SomeAppName.Models.MyViewModel 
@{ 
    ViewBag.Title = "Home Page"; 
} 
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 
@using (Html.BeginForm()) 
{ 
    @Html.LabelFor(m => m.NewPassword) 
    @Html.PasswordFor(m => m.NewPassword) 
    @Html.ValidationMessageFor(m => m.NewPassword) 
    <br/> 

    @Html.LabelFor(m => m.ConfirmPassword) 
    @Html.PasswordFor(m => m.ConfirmPassword) 
    @Html.ValidationMessageFor(m => m.ConfirmPassword) 

    <br/> 
    <input type="submit" value="OK" /> 
} 

En esta configuración c La validación lateral lient funciona perfectamente bien para todos los atributos, incluido el [Compare].

+0

Eso es lo mismo que he demostrado también. Me pregunto qué estoy haciendo de manera diferente, eso no es obvio. – beaudetious

+0

@beaudetious, es incluso menos obvio para aquellos de nosotros que no podemos ver su código fuente o podemos reproducir el error que está describiendo. Lo que viene a la mente es buscar errores de javascript con FireBug. –

+0

Gracias Darin. Hará. Si encuentro que es un error simple de mi parte (99% de probabilidad de que así sea), te marcaré como la respuesta. – beaudetious

8

Hay un ERROR en jquery .validate.unobtrusive.js (y jquery.validate.unobtrusive.min.js, la versión minimizada). La validación del lado del cliente emitida como resultado del atributo [Comparar] SÓLO funcionará si el campo de comparación es el PRIMER campo en el formulario. Para corregir este error, localice esta línea en jquery.validate.unobtrusive.js:

element = $(options.form).find(":input[name=" + fullOtherName + "]")[0]; 

que da lugar a esta equivalentes:

element = $(options.form).find(":input[name=MyExample.Control]")[0]; 

Desafortunadamente eso no es la sintaxis correcta para find(), y las causas para hacer referencia al primer control de entrada en el formulario.

Cambio esa línea para:

element = $(options.form).find(":input[name='" + fullOtherName + "']")[0]; 

que da lugar a esta equivalentes:

element = $(options.form).find(":input[name='MyExample.Control]'")[0]; 

Cuál es la sintaxis correcta y correctamente coincide con el control de entrada con el nombre especificado.

Localizar el mismo bloque de código en jquery.validate.unobtrusive.min.js, que se ve así:

f=a(b.form).find(":input[name="+d+"]")[0]; 

y cambiarlo a:

f=a(b.form).find(":input[name='"+d+"']")[0]; 
+0

Perfecto. ¡Esto debería haberse hecho la respuesta! He empleado el parche de Mark Shapiro en jquery.validate.unobtrusive.min.js y lo estoy usando junto con jQuery 1.8.2 y jQuery Validation Plugin 1.9.0; funciona como encanto :) – Kayes

1

nunca fue capaz de hacer la forma predeterminada de trabajar Parece que en JQuery solo se activan los métodos de validación que están registrados con JQuery.validator.

Inicialmente estaba haciendo algo como esto ...

jQuery.validator.unobtrusive.adapters.add("equaltopropertyvalidation", ["param"], function (rule) 
    { 
     alert("attaching custom validation adapter."); 
     rule.rules["equaltopropertyvalidation"] = rule.params.param; 
     rule.messages["equaltopropertyvalidation"] = rule.message; 

     return function (value, element, param) 
     { 
      alert("now validating!"); 
      return value == this.currentForm[param].value; 
     }; 
    }); 

Pero mi segunda alerta (ahora validar!) Nunca se dispararía a pesar de que el primero que lo haría. Había visto el artículo this, pero estaba dudando en implementarlo así porque me obliga a hacer algo más, pero era flojo.

Bueno, después de pasar mucho tiempo para descubrir lo que está mal lo implementé en la forma en que este artículo sugiere y funciona. Ahora es así y funciona.

<script type="text/javascript"> 

    jQuery.validator.addMethod("equaltopropertyvalidation", function (value, element, param) 
    { 
     return value == this.currentForm[param].value; 
    }); 

    jQuery.validator.unobtrusive.adapters.add("equaltopropertyvalidation", ["param"], function (rule) 
    { 
     rule.rules["equaltopropertyvalidation"] = rule.params.param; 
     rule.messages["equaltopropertyvalidation"] = rule.message; 
    }); 

</script> 

Si te gusta detalle a continuación, aquí está: Mire en jquery.validate.js y búsqueda de

 check: function (element) 

Ésta es la función que se dispara para comprobar si el campo es válida o no por disparando todas las reglas aplicables en el campo.Ahora primero crea una matriz o reglas para disparar. Lo hace usando el siguiente código.

 var rules = $(element).rules(); 

Luego se itera sobre la colección de reglas, crea un elemento de regla para cada elemento de la colección y luego trata de encontrar un método correspondiente al fuego para esa regla. Una vez que se encuentra el método, se dispara. Lo hace usando el siguiente código.

 var result = $.validator.methods[method].call(this, element.value.replace(/\r/g, ""), element, rule.parameters); 

Ahora lo importante es que si su método personalizado no se añade a la colección $ .validator.methods utilizando el JQuery.validator.addMethod TI no se encontrará, incluso si está sentado en el jQuery colección .validator.unobtrusive.adapters.

Puede haber una manera de hacer que esto funcione sin utilizar el JQuery.validator.addMethod (y si es así, que alguien aclare) pero esta es la razón por la que el segundo enfoque funciona y el primero no.

que estaba usando las siguientes versiones de los archivos Jquery

  1. JQuery: 1.6/1.7.1
  2. Jquery.Validate: 1.9.0
  3. JQuery.Unobtrusive.Validate: tomada de Microsoft CDN en 14/02/2012.
Cuestiones relacionadas