Проверка на стороне клиента DateTime не выполняется из-за форматирования - PullRequest
0 голосов
/ 27 сентября 2018

Я использую FluentValidation в проекте MVC5 без каких-либо проблем, кроме дат.Моя цель состоит в том, чтобы 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.Например, ложный отрицательный:

enter image description here

И ложный положительный:

enter image description here

Я ничего не делаю в jQuery Datepicker, прикрепленном к этим полям, кроме принудительной проверки поля сразу после выбора даты:

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

Все приложение использует локаль "en-US"по умолчанию.Все остальные проверки работают.

Я использую следующие версии библиотеки:

  • FluentValidation 8
  • jQuery 1.11.3
  • jQuery Validate1.17
  • jQuery Validate Unobtrusive 3.2.10 (Microsoft)

Я знаю, что мог бы написать собственный валидатор, который перед сравнением анализирует входные значения и значения диапазона в объектах JavaScript Date, нокажется, что должно быть что-то встроенное, чтобы все распознало эти строки как даты.

Чего мне не хватает?

1 Ответ

0 голосов
/ 28 сентября 2018

Проблема в том, что правило range в jquery.validate.js работает с числовыми значениями, а если оно не числовое, выполняется сравнение строк.

Вы можете переопределить поведение по умолчанию, добавив свое собственноеПравило сравнивать даты.Добавьте следующий сценарий после сценариев 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}", как объяснено в Указанное значение не соответствует требуемому формату гггг-мм-дд

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...