DateTime客户端验证由于格式化而失败 [英] DateTime client-side validation fails due to formatting

查看:198
本文介绍了DateTime客户端验证由于格式化而失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在MVC5项目中使用FluentValidation,除日期外没有任何问题.我的目标是让GreaterThanOrEqualTo客户端验证适用于一些日期字段.我知道当前文档没有将此方法列为受支持的客户端,但是它呈现了正确的jQuery验证数据属性.

在我的模型中,我有一个属性:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Display(Name = "Credit Decision Due Date")]
public DateTime? DueDate { get; set; }

在我看来,我使用的是标准Razor语法来绘制控制组:

<div class="control-group">
    @Html.LabelFor(m => m.DueDate, new { @class = "control-label text-bold" })
    @Html.TextBoxFor(m => m.DueDate, "{0:MM/dd/yyyy}", new { @class = "span12 date-picker" })
    @Html.ValidationMessageFor(m => m.DueDate)
</div>

在我的验证器中,只有一个简单的规则:

RuleFor(m => m.DueDate).GreaterThanOrEqualTo(DateTime.Today);

注意,我也尝试过InclusiveBetween((在文档中明确列出为受支持的客户端):

RuleFor(r => r.DueDate).InclusiveBetween(DateTime.Today, DateTime.Today.AddYears(1));

使用GreaterThanOrEqualTo呈现视图的结果是:

<div class="control-group">
    <label class="control-label text-bold" for="DueDate">Credit Decision Due Date <span class="text-error required-asterisk">*</span></label>
    <input class="span12 date-picker hasDatepicker" data-val="true" data-val-range="'Credit Decision Due Date' must be greater than or equal to '9/27/2018 12:00:00 AM'." data-val-range-max="" data-val-range-min="09/27/2018 00:00:00" data-val-required="'Credit Decision Due Date' must not be empty." id="DueDate" name="DueDate" type="text" value="">
    <span class="field-validation-valid help-block" data-valmsg-for="DueDate" data-valmsg-replace="true"></span>
</div>

到目前为止,我说的一切看起来都不错,除了运行客户端的验证行为不当外,几乎就像它将值视为 text 而不是Date一样.例如,假阴性:

还有误报:

除了在选择日期后立即强制字段进行验证之外,我没有在附加到这些字段的jQuery Datepicker中做任何事情:

$('.date-picker').datepicker({
    changeMonth: true,
    changeYear: true,
    onClose: function () {
        $(this).valid();
    }
});

默认情况下,整个应用程序使用"en-US"语言环境.所有其他验证都有效.

我正在使用以下库版本:

  • FluentValidation 8
  • jQuery 1.11.3
  • jQuery验证1.17
  • jQuery验证不干扰3.2.10(Microsoft)

我知道我可以编写一个自定义验证器,在比较之前将输入和范围值解析为JavaScript Date对象,但是似乎应该内置一些东西,以使所有内容都可以将这些字符串识别为日期.

我想念什么?

解决方案

问题是jquery.validate.js中的range规则适用于数字值,如果不是数字,则进行字符串比较.

您可以通过添加自己的规则来比较日期来覆盖默认行为.在validate*脚本之后但不在$(document).ready

内部添加以下脚本

$.validator.methods.range = function(value, element, param) {
    if ($(element).attr('data-val-date')) {
        var min = $(element).attr('data-val-range-min');
        var max = $(element).attr('data-val-range-max');
        var date = new Date(value).getTime();
        var minDate = new Date(min).getTime() || 0;
        var maxDate = new Date(max).getTime() || 8640000000000000;
        return this.optional(element) || (date >= minDate && date <= maxDate);
    }
    // use the default method
    return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
};

请注意,您的TextBoxFor()方法应生成一个data-val-date="The field Credit Decision Due Date must be a date."属性.我不确定是否只是从显示的结果html中省略了它,还是有一些其他代码忽略了它.如果未生成,则需要修改if ($(element).attr('data-val-date')) {代码行,例如使用类名

if ($(element).hasClass('date-picker')) {

请注意您的

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]

如果使用TextBoxFor(),则不需要

属性-仅在使用EditorFor()时才尊重这些属性,如果您确实使用EditorFor(),则格式字符串应采用ISO格式-即DataFormatString = "{0:yyyy-MM-dd}",如指定的值不符合要求的格式yyyy-MM-dd

I'm using FluentValidation in an MVC5 project without any issues except for dates. My goal is to have GreaterThanOrEqualTo client-side validation working for a few date fields. I know that the current documentation doesn't list this method as supported client-side, but it renders the correct jQuery Validation data attributes.

In my model, I have a property:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Display(Name = "Credit Decision Due Date")]
public DateTime? DueDate { get; set; }

In my view, I am using standard Razor syntax to draw the control group:

<div class="control-group">
    @Html.LabelFor(m => m.DueDate, new { @class = "control-label text-bold" })
    @Html.TextBoxFor(m => m.DueDate, "{0:MM/dd/yyyy}", new { @class = "span12 date-picker" })
    @Html.ValidationMessageFor(m => m.DueDate)
</div>

In my validator, there's just a simple rule:

RuleFor(m => m.DueDate).GreaterThanOrEqualTo(DateTime.Today);

Note, I have also tried InclusiveBetween, (which is explicitly listed as being supported client-side in the documentation):

RuleFor(r => r.DueDate).InclusiveBetween(DateTime.Today, DateTime.Today.AddYears(1));

The result of the view rendering with GreaterThanOrEqualTo is:

<div class="control-group">
    <label class="control-label text-bold" for="DueDate">Credit Decision Due Date <span class="text-error required-asterisk">*</span></label>
    <input class="span12 date-picker hasDatepicker" data-val="true" data-val-range="'Credit Decision Due Date' must be greater than or equal to '9/27/2018 12:00:00 AM'." data-val-range-max="" data-val-range-min="09/27/2018 00:00:00" data-val-required="'Credit Decision Due Date' must not be empty." id="DueDate" name="DueDate" type="text" value="">
    <span class="field-validation-valid help-block" data-valmsg-for="DueDate" data-valmsg-replace="true"></span>
</div>

Everything looks pretty good so far I'd say, except the validation running client side is misbehaving, almost like it's treating the value as text instead of a Date. For example, a false negative:

And and false positive:

I am not doing anything in the jQuery Datepicker attached to these fields other than forcing the field to validate immediately after picking a date:

$('.date-picker').datepicker({
    changeMonth: true,
    changeYear: true,
    onClose: function () {
        $(this).valid();
    }
});

The entire application uses an "en-US" locale by default. All other validation is working.

I'm using the following library versions:

  • FluentValidation 8
  • jQuery 1.11.3
  • jQuery Validate 1.17
  • jQuery Validate Unobtrusive 3.2.10 (Microsoft)

I know I could write a custom validator that parses the input and range values into JavaScript Date objects before comparing, but it seems like there should be something built-in to get everything to recognize these strings as dates.

What am I missing?

解决方案

The issue is that the range rule in jquery.validate.js works with numeric values, and if its not numeric, then it makes a string comparison.

You can override the default behavior by adding your own rule to compare dates. Add the following script after the validate* scripts but not inside $(document).ready

$.validator.methods.range = function(value, element, param) {
    if ($(element).attr('data-val-date')) {
        var min = $(element).attr('data-val-range-min');
        var max = $(element).attr('data-val-range-max');
        var date = new Date(value).getTime();
        var minDate = new Date(min).getTime() || 0;
        var maxDate = new Date(max).getTime() || 8640000000000000;
        return this.optional(element) || (date >= minDate && date <= maxDate);
    }
    // use the default method
    return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
};

Note that your TextBoxFor() method should be generating a data-val-date="The field Credit Decision Due Date must be a date." attribute. I am not sure if you just omitted that from the resulting html you have shown, or you have some other code that is omitting it. If its not being generated, then you would need to modify the if ($(element).attr('data-val-date')) { line of code, perhaps to use a class name, for example

if ($(element).hasClass('date-picker')) {

Note also that your

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]

attributes are not necessary if using TextBoxFor() - those attributes are only respected when using EditorFor(), and if you do use EditorFor(), then the format string should be in ISO format - i.e DataFormatString = "{0:yyyy-MM-dd}" as explained in The specified value does not conform to the required format yyyy-MM-dd

这篇关于DateTime客户端验证由于格式化而失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆