2011-12-04 13 views
8

Estoy usando MVC3 y quiero tener el formulario de inicio de sesión y el formulario de registro en la misma página. Para lograr que he construido LogInRegisterViewModel de la siguiente manera:MVC3 CompareAttribute, error del lado del cliente

public class LogInRegisterViewModel 
{ 
    public LogInViewModel LogIn { get; set; } 
    public RegisterViewModel Register { get; set; } 
} 

Me da lo que quiero (dos formas en la misma pantalla) y mensajes de datos para corregir los controladores y los retornos y muestra los errores de formas (si lo hay). El único problema que tengo es con CompareAttribute que tengo encima de la propiedad ConfirmPassword en mi RegisterViewModel:

public class RegisterViewModel 
{ 
    [Required] 
    [Display(Name = "Friendly user name")] 
    public string UserName { get; set; } 

    [Required] 
    [Display(Name = "E-mail address")] 
    public string Email { get; set; } 

    [Required] 
    [DataType(DataType.Password)] 
    [Display(Name = "Password")] 
    [StringLength(16, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 
    public string Password { get; set; } 

    [DataType(DataType.Password)] 
    [Display(Name = "Confirm password")] 
    [Compare("Password", ErrorMessage = "Passwords do not match.")] 
    public string ConfirmPassword { get; set; } 
} 

del lado del cliente las contraseñas no son iguales (~ siempre me dan un error de validación de Comparar con un mensaje que dice que no son iguales), incluso si lo son (estoy seguro de eso). HTML en el navegador es:

<div class="editor-label"> 
     <label for="Register_Password">Password</label> 
    </div> 
    <div class="editor-field"> 
     <input class="valid" data-val="true" data-val-length="The Password must be at least 6 characters long." data-val-length-max="16" data-val-length-min="6" data-val-required="The Password field is required." id="Register_Password" name="Register.Password" type="password"> 
     <span class="field-validation-valid" data-valmsg-for="Register.Password" data-valmsg-replace="true"></span> 
    </div> 

    <div class="editor-label"> 
     <label for="Register_ConfirmPassword">Confirm password</label> 
    </div> 
    <div class="editor-field"> 
     <input class="input-validation-error" data-val="true" data-val-equalto="Passwords do not match." data-val-equalto-other="*.Password" id="Register_ConfirmPassword" name="Register.ConfirmPassword" type="password"> 
     <span class="field-validation-error" data-valmsg-for="Register.ConfirmPassword" data-valmsg-replace="true"><span class="" generated="true" for="Register_ConfirmPassword">Passwords do not match.</span></span> 
    </div> 

Tengo la sensación de que todo se trata de este atributo: datos-val-equalto-otra = "* Contraseña"

CompareAttribute funciona bien, cuando uso RegisterViewModel directamente. ¿Alguien ha entrado en esto antes? ¿Es un error o estoy haciendo algo mal? ¿Cómo hacer que Compare para trabajar en mi caso?

Respuesta

15

Debería funcionar con el atributo [Compare("Password", ErrorMessage = "Passwords do not match.")] pero parece que esto es realmente un error en el archivo jquery.validate.unobtrusive.js. El problema es que en este código:

adapters.add("equalto", ["other"], function (options) { 
    var prefix = getModelPrefix(options.element.name), 
     other = options.params.other, 
     fullOtherName = appendModelPrefix(other, prefix), 
     element = $(options.form).find(":input[name=" + fullOtherName + "]")[0]; 

    setValidationValues(options, "equalTo", element); 
}); 

Por lo tanto, trata de encontrar otro control con el jQuery encontrar el método. Pero el "." No se ha escapado el carácter dot en la variable fullOtherName (en su caso contendrá: "Register.Password") como se describe en este SO question. Esa es la razón por la que funciona cuando solo usa RegisterViewModel directamente porque entonces no hay puntos en los nombres.

solucionarlo es necesario añadir una línea a la función appendModelPrefix:

//original 
function appendModelPrefix(value, prefix) { 
    if (value.indexOf("*.") === 0) { 
     value = value.replace("*.", prefix); 
    } 
    return value; 
} 

//fixed 
function appendModelPrefix(value, prefix) { 
    if (value.indexOf("*.") === 0) { 
     value = value.replace("*.", prefix); 
    } 
    value = value.split('.').join('\\.'); 
    return value; 
} 
+0

Funciona como un encanto, gracias. –

+1

Incluso esta revisión tiene un error propio. Javascript ".replace" solo reemplaza la primera instancia de "." e ignora el resto. En modelos complejos, cualquier propiedad que tendría más de un período sufriría el mismo destino que el código original. Para solucionarlo, debe usar: value = value.split ('.'). Join ('\\.'); –

+0

@NickBork nice catch :). He actualizado mi respuesta. – nemesv

0

muy buena respuesta, nemesv.

Sólo hay una cosa que añadir para los novatos:

function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a} 

convierte

function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);a=a.split('.').join('\\.');return a} 

en .min.js

lo contrario cuando se publica, el error vuelve a aparecer.

Cuestiones relacionadas