Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
360 views
in Technique[技术] by (71.8m points)

asp.net mvc 3 - JQuery 1.5 breaks Compare Validate (JQuery Validate 1.8)

After upgrading to JQuery 1.5 and later 1.5.1, my compare validation fails. I'm using JQuery.Validate 1.7. My ViewModel has the following data annotations:

/// <summary>
/// Gets or sets the full name.
/// </summary>
/// <value>The full name.</value>
[Required]
[Display(Name = "fullname", ResourceType = typeof(Milkshake.Commerce.Model.Resources.Text))]
public string FullName { get; set; }

/// <summary>
/// Gets or sets the email.
/// </summary>
/// <value>The email.</value>
[DataType(DataType.EmailAddress)]
[Display(Name = "email", ResourceType = typeof(Milkshake.Commerce.Model.Resources.Text))]
[Required(ErrorMessageResourceName = "EmailRequired", ErrorMessageResourceType = typeof(Milkshake.Commerce.Model.Resources.ValidationMessages))]
[RegularExpression(@"w+([-+.']w+)*@w+([-.]w+)*.w+([-.]w+)*", ErrorMessageResourceType = typeof(Milkshake.Commerce.Model.Resources.ValidationMessages), ErrorMessageResourceName = "EmailInvalid")]
public string Email { get; set; }

/// <summary>
/// Gets or sets the password.
/// </summary>
/// <value>The password.</value>
[DataType(DataType.Password)]
[Display(Name = "password", ResourceType = typeof(Milkshake.Commerce.Model.Resources.Text))]
[Required(ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(Milkshake.Commerce.Model.Resources.ValidationMessages))]
[ValidatePasswordLengthAttribute(ErrorMessageResourceName = "PasswordLength", ErrorMessageResourceType = typeof(Milkshake.Commerce.Model.Resources.ValidationMessages))]
public string Password { get; set; }

/// <summary>
/// Gets or sets the confirm password.
/// </summary>
/// <value>The confirm password.</value>
[DataType(DataType.Password)]
[Display(Name = "confirmPassword", ResourceType = typeof(Milkshake.Commerce.Model.Resources.Text))]
[Required(ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(Milkshake.Commerce.Model.Resources.ValidationMessages))]
[Compare("Password", ErrorMessageResourceName = "PasswordsMustMatch", ErrorMessageResourceType = typeof(Milkshake.Commerce.Model.Resources.ValidationMessages))]
public string ConfirmPassword { get; set; }

What ever value I enter, the password fields are never identical.

UPDATE - ASP.NET AntiForgeryToken gets in trouble.

After fooling around in FireBug setting breakpoints, I noticed that in the equalTo validation function, starting on line 1065 in jquery.validate.js, the target element that is found, is not the Password field - but the __RequestVerificationToken that ASP.NET MVC writes when you use the Html.AntiForgeryToken() helper.

So that means we're not even comparing the correct input elements. To work around this issue, I added a dirty hack to the jquery.validate.js file:

// http://docs.jquery.com/Plugins/Validation/Methods/equalTo
equalTo: function (value, element, param) {
    // bind to the blur event of the target in order to revalidate whenever the target field is updated
    // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
    var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function () {
        $(element).valid();
    });

    if ($(target).is("input[type=hidden]") && $(target).attr("name") == "__RequestVerificationToken") {
        var otherElementId = $(element).attr("id");
        var underScoreIndex = otherElementId.indexOf("_");
        otherElementId = otherElementId.substring(0, underScoreIndex + 1);
        otherElementId += $(element).attr("data-val-equalto-other").substring(2);

        target = $("#" + otherElementId);
    }

    return value == target.val();
}

This hack, takes the data-val-equalto-other attribute's value, and mixes it with its own ID, to find the correct input element. Won't work in all cases. But works for me, in the above case.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I've found that this is due to an error in jquery.validate.unobtrusive.js

The code in Unobtrusive adds an equalto adapter that tries to find the matching element by its name attribute, using the following code:

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

The fullOtherName variable is often (and probably always) namespaced with a period, so the jQuery selector returns too many inputs, and selects the very first one. The period needs to be escaped with .replace(".", "\."), giving you:

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

A similar construct exists a few lines lower, and will also need to be fixed (as well as the minified Javascript).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...