JQuery 1.5 breaks Compare Validate (JQuery Validat

2019-01-22 23:09发布

问题:

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.

回答1:

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).



回答2:

If it is still relevant, i had the same issue, upgraded all the scripts and now it works. Im using the following: Jquery 1.8 (official version from their cdn), Jquery validation 1.9 and jquery unobtrusive validation from the latest package provided by microsoft on nunget (which, weirdly, gets u jquery validation 1.8 and not 1.9). God bless microsoft and the mess the manage to make with 3 script files :\



回答3:

You can use the latest versions of jquery and jquery.validate off the Microsoft CDN. I can't see an updated version of jquery.validate.unobtrusive.min.js.

The version of jquery.validate.unobtrusive.min.js shipped with MVC4 works fine.

<!-- Scripts -->
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/jquery.validate/1.10.0/jquery.validate.min.js"></script>
<!-- ToDo: Will Microsoft fix this on the CDN? -->
<script type="text/javascript" src="@Url.Content("~/Scripts/Frameworks/jquery.validate.unobtrusive.min.js")"></script>


回答4:

From http://bassistance.de/jquery-plugins/jquery-plugin-validation/

Please note: The latest release isn’t, yet, compatible with jQuery 1.5.x. You can find a compatible version in the GitHub repository.

However, none of the branches works for me...



回答5:

In response to MartinHN's update, I have encountered the same problem and applied the same fix. As I am using Nested Editor Templates, I had multiple underscrores in my otherElementId and so changed his code to use the lastIndexOf rather than indexOf. E.g.

var underScoreIndex = otherElementId.indexOf("_");

was changed to :

var underScoreIndex = otherElementId.lastIndexOf("_");


回答6:

It looks like if you look at new MVC4 code. You can see the new version of jquery.validate.unobtrusive.js: http://code.msdn.microsoft.com/ASPNET-MVC-4-Mobile-e99ed0ed/sourcecode?fileId=49443&pathId=640259357 If you do a diff. It is exactly the same as the MVC3 version except with the minor changes mentioned above done in a different way. So it should be all you have to do is replace your jquery.validate.unobtrusive.js with the one in the code example and all will work.

Just so you know. I am using Jquery 1.6.4 with Jquery mobile 1.0.1