我正在尝试为 nullable<decimal>
实现客户端验证其小数点分隔符可以是逗号(例如: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...
}
我的 jQueryFixes 覆盖了 jquery.validate.js
range()
的文件和 number()
:
$.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);
}
...正如许多关于此问题的帖子/问题中所建议的那样(例如:here 或 here)。
奇怪的是:
当我尝试提交诸如 123,45 之类的值时,即使我已经使用 Firebug 调试了脚本并看到我的覆盖函数正在被调用并返回 true,我还是无法提交表单.相反,无论出于何种原因,我的十进制值的 EditorFor 都受到关注,我似乎无法找出原因。
(我相信我的服务器端验证 - 使用自定义 Binder 等 - 工作正常并且不是这里的问题:我需要一些关于如何获取表单的帮助提交或为什么输入字段得到焦点,即使它看起来有效。)
编辑 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 之后):
<script type="text/javascript">
...
$( 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]);
}
});
...
</script>
...但我仍然面临同样的问题:validator.methods.number
正在返回 true 但未提交表单,而是输入字段获得焦点。
如果我在提交时检查输入元素,我可以看到它很快从 class="valid"
开始至 class='input-validation-error'
然后回到valid
.很奇怪。
结论:
@LeftyX 为发现相同问题的人提供了一个非常好的和完整的解决方案。
我已经为可为 null 的小数创建了一个自定义模型绑定(bind)器,但是全局化脚本以及在 Model/ViewModel 中包含文化肯定会派上用场。
我的问题的另一个原因可能是我(不小心)两次包含一些脚本。
更新(2015 年 7 月):
globalize.js现在有点不同了。引用至 this answer和 the documentation更新步骤。
最佳答案
我为此苦苦挣扎。
对我来说最好的方法是为小数定义一个自定义 Binder :
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;
}
}
并将其绑定(bind)到 Global.asax
中的 Application_Start
中:
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
我还使用可以找到的全局化脚本(带有文化)here或从 nuget 下载 here .
您的包应如下所示:
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));
}
并自定义您的验证(我也添加了日期)。您已经在 jQueryFixes
中完成了该操作。
您可以找到一个工作示例 here (MvcAppForDecimals) 您可以在其中更改语言 使用工具栏和 cookie,这样文化也可以在服务器上改变。
在示例中,我读取 Application_BeginRequest
中的 cookie 或使用 web.config 中定义的默认区域性:
<globalization enableClientBasedCulture="true" uiCulture="en-GB" culture="en-GB" />
我还定义了一个 ActionFilter (LanguageFilterAttribute),它将当前文化注入(inject)到基础 View 模型中,以便客户端使用服务器端的当前集。
可以找到扩展说明here .
关于全局化脚本和文化设置的更多信息 here .
关于javascript - 小数、逗号和客户端验证问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20263762/