小数,逗号和客户端validation问题

我正在尝试为nullablenullable实现客户端validation,其小数分隔符可以是逗号(例如:123,45)。

在我看来:

 ... 
@Html.LabelFor(model => model.Turnover)
@Html.EditorFor(model => model.Turnover) @Html.ValidationMessageFor(model => model.Turnover)
... @section Scripts { @Styles.Render("~/Content/themes/base/css") @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/jqueryui") @Scripts.Render("~/bundles/jqueryval") @Scripts.Render("~/bundles/jQueryFixes") ...scripts for this view... }

我的jQueryFixes覆盖了range()number() jquery.validate.js文件:

 $.validator.methods.range = function (value, element, param) { var globalizedValue = value.replace(",", "."); return this.optional(element) || (globalizedValue >= param[0] && globalizedValue <= param[1]); } $.validator.methods.number = function (value, element) { return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[\s\.,]\d{3})+)(?:[\.,]\d+)?$/.test(value); } 

……正如关于这个问题的许多post/问题所建议的那样(例如: 这里或这里 )。

很奇怪的是:

当我尝试提交一个像123,45这样的值时,即使我用Firebug调试了脚本并看到我的overrode函数被调用并返回true,我也无法提交表单。 相反,我的EditorFor for decimal值因为任何原因而被集中,我似乎无法找出原因。

(我相信我的服务器端validation – 使用自定义绑定器等 – 工作正常,这不是问题 :我想要一些帮助,如何让表单提交或为什么输入字段集中即使它看起来有效。)

编辑1:

附加信息。 在我的BundlesConfig.cs中:

 bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); ... bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include( "~/Scripts/jquery-ui-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.unobtrusive*", "~/Scripts/jquery.validate*")); bundles.Add(new ScriptBundle("~/bundles/jQueryFixes").Include( "~/Scripts/jQueryFixes.js")); ... 

编辑2:

在@LeftyX建议之后,我尝试使用Globalize脚本(在删除我的jQueryFixes.js之后):

  ... $( document ).ready(function() { Globalize.culture("en-US", "pt-PT"); }); $.validator.methods.number = function (value, element) { return this.optional(element) || jQuery.isNumeric(Globalize.parseFloat(value)); } //Fix the range to use globalized methods jQuery.extend(jQuery.validator.methods, { range: function (value, element, param) { var val = Globalize.parseFloat(value); return this.optional(element) || (val >= param[0] && val <= param[1]); } }); ...  

…但我仍然面临同样的问题: validator.methods.number返回true但表单未提交,输入字段被重点关注。

如果我在提交时检查输入元素,我可以看到它很快从class="valid"变为class='input-validation-error'然后又变回valid 。 很奇怪。

结论:

@LeftyX为发现相同问题的人提供了一个非常好的完整解决方案。

我已经有了一个可以为空的小数的自定义模型绑定器,但全球化脚本和包含Model / ViewModel中的文化肯定会派上用场。

我的问题的另一个原因可能是我(意外)包括一些脚本两次。

更新(2015年7月):

globalize.js现在有点不同了。 参考。 这个答案和更新步骤的文档 。

我对此很挣扎。

对我来说最好的方法是为小数定义一个自定义绑定器:

 public class DecimalModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { ValueProviderResult valueResult = bindingContext.ValueProvider .GetValue(bindingContext.ModelName); ModelState modelState = new ModelState { Value = valueResult }; object actualValue = null; try { //Check if this is a nullable decimal and a null or empty string has been passed var isNullableAndNull = (bindingContext.ModelMetadata.IsNullableValueType && string.IsNullOrEmpty(valueResult.AttemptedValue)); //If not nullable and null then we should try and parse the decimal if (!isNullableAndNull) { actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture); } } catch (FormatException e) { modelState.Errors.Add(e); } bindingContext.ModelState.Add(bindingContext.ModelName, modelState); return actualValue; } } 

并将其绑定在Global.asax中的Application_Start中:

 ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder()); ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder()); 

我还使用了globalize脚本(带有文化),可以在这里找到或者从nuget下载。

你的包应该是这样的:

 bundles.Add(ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js", "~/Scripts/globalize.js", "~/Scripts/cultures/globalize.culture.en-GB.js", "~/Scripts/cultures/globalize.culture.it-IT.js" )); 

当然,如果要支持不同的本地化,可以添加更多的文化。

现在,当您的DOM准备就绪(javascript)时,您可以定义您的文化:

 Globalize.culture('en-GB'); $.validator.methods.number = function (value, element) { return this.optional(element) || jQuery.isNumeric(Globalize.parseFloat(value)); } //Fix the range to use globalized methods jQuery.extend(jQuery.validator.methods, { range: function (value, element, param) { var val = Globalize.parseFloat(value); return this.optional(element) || (val >= param[0] && val <= param[1]); } }); $.validator.methods.date = function (value, element) { return (this.optional(element) || Globalize.parseDate(value)); } 

并自定义您的validation(我也添加了日期)。 你已经在jQueryFixes完成了。

您可以在这里找到一个工作示例(MvcAppForDecimals),您可以使用工具栏和cookie更改语言,以便文化也可以在服务器上更改。

在示例中,我在Application_BeginRequest读取cookie或使用web.config中的默认文化定义:

  

我还定义了一个ActionFilter(LanguageFilterAttribute),它在基本视图模型中注入当前文化,以便客户端使用服务器端的当前集合。

可在此处找到扩展说明。

有关全球化脚本和文化设置的更多信息,请点击此处 。

关于globalize.js的一个小更新。 现在情况有点不同(而且令人困惑):

包括脚本如下:

        

现在我们需要将I18n内容加载到Globalize :

  

I18n内容在此处以JSON格式提供。

如果你的getJSON()上有404,请记得添加:

  (...)     

在您的Web.config(ASP .NET MVC应用程序)中。