JQuery 1.5导致Compare Validate(JQuery Validate 1.8)失效

7

在升级到JQuery 1.5及更高版本1.5.1后,我的比较验证失败了。我正在使用JQuery.Validate 1.7版本。我的ViewModel具有以下数据注释:

/// <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; }

无论我输入什么值,密码字段都不相同。
更新 - ASP.NET AntiForgeryToken出了问题。
在FireBug中设置断点后,我注意到在equalTo验证函数中(在jquery.validate.js的第1065行开始),找到的目标元素不是密码字段,而是ASP.NET MVC在使用Html.AntiForgeryToken()助手时编写的__RequestVerificationToken。
这意味着我们甚至没有比较正确的输入元素。为了解决这个问题,我向jquery.validate.js文件添加了一个不好的hack。
// 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();
}

这个技巧会取出data-val-equalto-other属性的值,并将其与自身的ID混合在一起,以找到正确的输入元素。这种方法并不能适用于所有情况,但在上述情况下对我很有用。
6个回答

11

我发现这是由于jquery.validate.unobtrusive.js中的一个错误引起的。

Unobtrusive中的代码添加了一个equalto适配器,该适配器尝试通过其名称属性查找匹配的元素,使用以下代码:

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

fullOtherName变量通常(甚至可能总是)使用句点进行命名空间处理,因此jQuery选择器返回过多的输入并选择第一个。需要使用.replace(".", "\\.")对句点进行转义,得到:

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

还有一个类似的结构在几行后面,也需要修复(以及压缩的Javascript)。


它能正常工作!不知道这个 bug 是否已经在微软的宇宙中被报告了。我应该通过 Microsoft Connect 报告它,以便在下一个版本中修复它。 - MartinHN
代码已经修复。谢谢。http://connect.microsoft.com/VisualStudio/feedback/details/665793/jquery-unobtrusive-validate-equalto-fails-with-compare-attribute - jsgoupil
1
这非常有帮助!但是在我的情况下,我不得不将其更改为element = $(options.form).find(":input[name='" + fullOtherName.replace(".", "\.") + "']")[0]; 注意注入值周围的单引号。别忘了在压缩版本中修复它! :) - Dmitry Selitskiy
您可以从 Microsoft CDN 上获取最新版本的 jQuery 和 jQuery.validate,但我没有看到 jquery.validate.unobtrusive.min.js 的更新。 - Dave Watts

2
如果还有用的话,我曾经遇到过同样的问题,升级了所有脚本,现在它可以工作了。 我使用以下内容:Jquery 1.8(从他们的CDN获取的官方版本),Jquery validation 1.9以及从Microsoft最新提供的nunget包中获取的jquery unobtrusive validation(奇怪的是,它会得到jquery validation 1.8而不是1.9)。上帝保佑微软和他们管理的三个脚本文件的混乱。

1

您可以使用最新版本的jquery和jquery.validate从Microsoft CDN下载。我没有看到jquery.validate.unobtrusive.min.js的更新版本。

MVC4附带的jquery.validate.unobtrusive.min.js版本可以正常使用。

<!-- 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>

0

如果你查看新的MVC4代码,似乎可以看到jquery.validate.unobtrusive.js的新版本: http://code.msdn.microsoft.com/ASPNET-MVC-4-Mobile-e99ed0ed/sourcecode?fileId=49443&pathId=640259357 如果你进行比较,它与MVC3版本完全相同,只是以不同的方式完成了上述微小的更改。因此,你只需要用示例代码中的jquery.validate.unobtrusive.js替换你的文件,一切都会正常工作。

只是让你知道。我正在使用Jquery 1.6.4和Jquery mobile 1.0.1


0
作为对MartinHN更新的回应,我遇到了同样的问题并采用了相同的解决方法。由于我正在使用嵌套编辑器模板,我的otherElementId中有多个下划线,因此我更改了他的代码以使用lastIndexOf而不是indexOf。例如:
var underScoreIndex = otherElementId.indexOf("_");

被更改为:

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

0

实际上,它甚至在1.5版本中都无法正常工作。我想我们必须等待他们解决这些问题 :( - MartinHN
谢谢,马丁!我的问题是我没有使用防伪令牌;-) - Jakub Konecki
我们已经停止使用这个插件了 - 无法确定你的黑客是否能帮助我。 - Jakub Konecki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接