Javascript 小数、逗号和客户端验证问题

Javascript 小数、逗号和客户端验证问题,javascript,jquery,validation,asp.net-mvc-4,Javascript,Jquery,Validation,Asp.net Mvc 4,我正在尝试为一个可为null的实现客户端验证,它的十进制分隔符可以是逗号(例如:123,45) 我认为: ... <div class="editor-label"> @Html.LabelFor(model => model.Turnover) </div> <div class="editor-field"> @Html.EditorFor(model => model.Turnover) @Html.Validati

我正在尝试为一个可为null的
实现客户端验证,它的十进制分隔符可以是逗号(例如:123,45)

我认为:

...

<div class="editor-label">
    @Html.LabelFor(model => model.Turnover)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Turnover)
    @Html.ValidationMessageFor(model => model.Turnover)
</div>

...

@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...
}
…正如许多关于这个问题的帖子/问题所建议的那样(例如:或)

奇怪的是:

当我试图提交一个值,比如123,45,即使我已经用Firebug调试了脚本,并且看到我的overrode函数正在被调用并返回true,我也无法提交表单。相反,无论出于什么原因,我的十进制值编辑器都在关注,我似乎无法找到原因

(我相信我的服务器端验证(使用自定义活页夹等)工作正常,不是这里的问题:我希望获得一些帮助,了解如何提交表单,或者为什么输入字段即使看起来有效,也会变得重点突出。)

编辑1:

其他信息。在my BundleConfig.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之后):


...
$(文档).ready(函数(){
全球化。文化(“en-US”、“pt-pt”);
});
$.validator.methods.number=函数(值,元素){
返回此.optional(element)| | jQuery.isNumeric(Globalize.parseFloat(value));
}
//修正使用全球化方法的范围
extend(jQuery.validator.methods{
范围:函数(值、元素、参数){
var val=Globalize.parseFloat(值);

返回这个。可选的(元素)| |(val>=param[0]&&val我对此做了很多努力

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

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;
    }
}
并将其绑定到
全局.asax中的
应用程序\u 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));
}
我还定义了一个ActionFilter(LanguageFilterAttribute),它将当前区域性注入到基本视图模型中,以便客户端使用服务器端的当前集

可以找到扩展的解释


有关全球化脚本和区域性设置的更多信息。

只是一个关于全球化脚本和区域性设置的小更新。现在情况有点不同(而且令人困惑):

包括以下脚本:

<!--
First, we load Globalize's dependencies (`cldrjs` and its supplemental
module).
-->
<script type="text/javascript" src="~/Scripts/cldr.js"></script>
<script type="text/javascript" src="~/Scripts/cldr/event.js"></script>
<script type="text/javascript" src="~/Scripts/cldr/supplemental.js"></script>

<!--
Next, we load Globalize and its modules.
-->
<script type="text/javascript" src="~/Scripts/globalize.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/number.js"></script>

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

嘿,回答得非常好且完整,谢谢。我已经有了DecimalModelBinder,但这不是问题所在,因为我正在努力进行客户端验证(即表单甚至没有提交到服务器,以便ModelBinder可以完成其工作)。虽然我添加了Globalize脚本,但我仍然面临相同的问题:好像验证正在接受值,但其他东西阻止提交。谢谢。问题可能是服务器和客户端使用不同的区域性。Globalize脚本和DecimalModelBinder允许您避免检查逗号或点为小数,但您必须设置要使用的区域性。您可以查看我的示例代码。对于如此简单的事情,这是一项大量的工作!您的工作示例也是一个很大的帮助。谢谢&upvote。@user1987392:很高兴我提供了帮助。干杯。有问题//请修复使用全球化方法的范围。执行此操作后代码,客户端验证无效。浏览器自动将表单提交到服务器而无需客户端验证。我不确定原因。
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));
}
<globalization enableClientBasedCulture="true" uiCulture="en-GB" culture="en-GB" />
<!--
First, we load Globalize's dependencies (`cldrjs` and its supplemental
module).
-->
<script type="text/javascript" src="~/Scripts/cldr.js"></script>
<script type="text/javascript" src="~/Scripts/cldr/event.js"></script>
<script type="text/javascript" src="~/Scripts/cldr/supplemental.js"></script>

<!--
Next, we load Globalize and its modules.
-->
<script type="text/javascript" src="~/Scripts/globalize.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/number.js"></script>
<script type='text/javascript'>

    // At this point, we have Globalize loaded. But, before we can use it, we
    // need to feed it on the appropriate I18n content (Unicode CLDR). In order
    // to do so, we use `Globalize.load()` and pass the content.

    $.when($.getJSON('/Scripts/cldr/supplemental/likelySubtags.json'),
               $.getJSON('/Scripts/cldr/main/en-GB/numbers.json'),
               ...other locales...
               $.getJSON('/Scripts/cldr/supplemental/numberingSystems.json'))
        .done(function (result1, result2, result3, result4) {
            Globalize.load(result1[0]); //contains data of first executed request
            ...load the other ones...
            Globalize.load(result3[0]); //contains data of third executed request
            Globalize.load(result4[0]); //contains data of fourth executed request

            var glob = Globalize([YOUR-LOCALE]); // e.g. en-UK, pt-PT, pt-BR, es-ES, etc.

            $.validator.methods.number = function (value, element) {
                var number = glob.parseNumber(value);
                return this.optional(element) || jQuery.isNumeric(number);
            }

            //Fix the range to use globalized methods
            jQuery.extend(jQuery.validator.methods, {
                range: function (value, element, param) {
                    var val = glob.formatNumber(value);
                    return this.optional(element) || (val >= param[0] && val <= param[1]);
                }

        });
    });

</script>
<system.webServer>

    (...)

    <staticContent>
      <mimeMap fileExtension=".json" mimeType="application/json" />
    </staticContent>

</system.webServer>