Я не могу проверить поле даты и времени в форме

Я использую этот объект:

[Required]
[Display(Name = "AuditDate", ResourceType = typeof(Resources.Audit))]
[DisplayFormat(DataFormatString = "{dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime dateAudit { get; set; }

В этой части моей формы:

@Html.TextBox("dateAudit", String.Format("{0:d}", Model.dateAudit.ToString("dd'/'MM'/'yyyy"), new { @class = "form-control" }))

Когда я пытаюсь ввести дату, я не могу отправить форму (появляется диалоговое окно DatePicker), потому что есть проблема с полем. Я добавил ValidationMessageFor в поле, которое говорит мне, что поле не содержит допустимую дату:

@Html.ValidationMessageFor(model => model.dateAudit, "", new { @class = "text-danger" })

Это сообщение об ошибке HTML, сгенерированное в этот момент для этого поля:

<input data-val="true" data-val-date="The field Date must be a date." data-val-required="The field Date is required." id="dateAudit" name="dateAudit" type="text" value="10/03/2015" class="hasDatepicker input-validation-error">

Я также попытался установить культуру для всех приложений в файле конфигурации:

<globalization uiCulture="fr-FR" culture="fr-FR" />

Если я выберу дату, например 1 марта, в формате 01/03/2015, проблем не будет, и привязка модели распознает ее, но когда я выберу 20 марта, поле не пройдет проверку (я подозреваю, что оно думает, что я пытаюсь ввести 20 как месяц).

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

Спасибо за вашу помощь.

РЕДАКТИРОВАТЬ: я забыл посоветовать вам, что я использовал это переопределение jquery ui для datepicker:

/* French initialisation for the jQuery UI date picker plugin. */
/* Written by Keith Wood (kbwood{at}iinet.com.au),
              Stéphane Nahmani ([email protected]),
              Stéphane Raimbault <[email protected]> */
(function (factory) {
    if (typeof define === "function" && define.amd) {

        // AMD. Register as an anonymous module.
        define(["../datepicker"], factory);
    } else {

        // Browser globals
        factory(jQuery.datepicker);
    }
}(function (datepicker) {

    datepicker.regional['fr'] = {
        closeText: 'Fermer',
        prevText: 'Précédent',
        nextText: 'Suivant',
        currentText: 'Aujourd\'hui',
        monthNames: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',
            'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
        monthNamesShort: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',
            'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],
        dayNames: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
        dayNamesShort: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
        dayNamesMin: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],
        weekHeader: 'Sem.',
        dateFormat: 'dd/mm/yy',
        firstDay: 1,
        isRTL: false,
        showMonthAfterYear: false,
        yearSuffix: ''
    };
    datepicker.setDefaults(datepicker.regional['fr']);

    return datepicker.regional['fr'];

}));

person clement    schedule 10.03.2015    source источник
comment
Ваш String.Format должен содержать new { @class = "form-control" } внутри него? Я думаю, что это должно быть вне вызова метода формата.   -  person cbr    schedule 10.03.2015
comment
Спасибо за ваш ответ @GrawCube! Form-control — это класс CSS, применяемый к входным данным, чтобы стилизовать их с помощью начальной загрузки Twitter. Я не думаю, что это вносит какие-то изменения для проверки. Я только что попытался удалить этот класс, проблема все еще есть.   -  person clement    schedule 10.03.2015
comment
jquery Globalize должен работать. Какую версию jQuery вы используете?   -  person    schedule 10.03.2015
comment
@StephenMuecke: еще раз спасибо :-) jquery Globalize, я не хочу его использовать, потому что он недостаточно совместим с браузером для клиентов... github.com/jquery/globalize#browser-support   -  person clement    schedule 10.03.2015


Ответы (4)


Вы можете создать свой собственный метод, чтобы переопределить метод jquery.validator по умолчанию. Обратите внимание, что следующий код, вероятно, является излишним для того, что вам нужно (это часть моего собственного плагина для помощника @Html.DatePicker(), который отображает средство выбора даты на основе сервера CultureInfo)

// Override default date validator format to allow culture specific format
$.validator.methods.date = function (value, element) {
  return this.optional(element) || globalDate(value).isValid();
};

Примечание. Не заключайте вышеуказанный метод в document.ready().

Date.prototype.isValid = function () {
  return !isNaN(this.getTime());
}

var inputFormat = 'dd/MM/yyyy';

// datepicker.prototype.globalDate = function (value) {
function globalDate(value) {
  // Initialise a new date
  var date = new Date(0);
  if (value == undefined) {
    // Return todays date
    return date; // adjust to suit your needs
  }
  // Get the components of the format
  // The separator can be forward slash, hyphen, dot and/or space
  var regex = new RegExp(/([dMy]+)([\s/.-]+)([dMy]+)([\s/.-]+)([dMy]+)/);
  var format = regex.exec(inputFormat);
  // Get the components of the value
  regex = new RegExp(/(\d+)([\s/.-]+)(\d+)([\s/.-]+)(\d+)/);
  value = regex.exec(value);
  // Check the value is valid
  if (value === null || value[2] !== format[2] || value[4] !== format[4]) {
    // Its not valid
    date.setTime(Number.NaN);
    return date;
  }
  // TODO: What if year entered as 2 digits?
  var day = Number.NaN;
  var month = Number.NaN;
  var year = Number.NAN;
  if (format[1].charAt(0) === 'd') {
    // little-endian (day, month, year)
    day = parseInt(value[1]);
    month = parseInt(value[3]) - 1;
    year = parseInt(value[5]);
  } else if (format[1].charAt(0) === 'M') {
    // middle-endian (month, day, year)
    day = parseInt(value[3]);
    month = parseInt(value[1]) - 1;
    year = parseInt(value[5]);
  } else {
    // big endian (year, month, day)
    day = parseInt(value[5]);
    month = parseInt(value[3]) - 1;
    year = parseInt(value[1]);
  }
  date.setFullYear(year);
  date.setMonth(month);
  date.setDate(day);
  // Check its valid
  if (date.getDate() !== day || date.getMonth() !== month || date.getFullYear() !== year) {
    date.setTime(Number.NaN);
    return date;
  }
  return date;
}

Изменить: на основе отредактированного вопроса (OP использует средство выбора даты пользовательского интерфейса jQuery), это может быть просто

$.validator.addMethod('date', function (value, element) {
  if (this.optional(element)) {
    return true;
  }
  var valid = true;
  try {
    $.datepicker.parseDate('dd/mm/yy', value);
  }
  catch (err) {
    valid = false;
  }
  return valid;
});
$('#dateAudit').datepicker({ dateFormat: 'dd/mm/yy' });

Боковое примечание: рекомендуется использовать строго типизированный помощник и передать строку формата

@Html.TextBoxFor(m => m.dateAudit, "{0:dd/MM/yyyy}")
person Community    schedule 10.03.2015
comment
К вашему сведению, у первого метода есть СЕРЬЕЗНЫЙ недостаток. Вы создаете новую дату (текущую дату) с помощью var date = new Date();. Если Хэллоуин (ура сегодня), то эта дата становится 31.10.2018. Допустим, вы проверяете 01.06.2018. Если вы сначала замените год (date.setFullYear(year);), а затем месяц (июнь) ДО того, как вы установите день, вы получите 31.06.2018. Итак, прежде чем вы сможете даже добраться до строки, которая читает date.setDate(day); у вас уже есть неверная дата. Вы можете сначала попытаться установить дату, но если вы проверяете дату 31, а это просто февраль, вы тоже в ручье. Этот метод не работает - person Brian Lorraine; 31.10.2018
comment
Возможно, прежде чем вы выполните setmonth,setfullear,setdate для объекта даты, сначала установите дату и месяц на 1. Затем сделайте это снова с реальными числами, которые вы хотите изменить. - person Brian Lorraine; 31.10.2018
comment
@BrianLorraine, спасибо, это должно было быть var date = new Date(0); (теперь обновлено) - person ; 01.11.2018

Если вы не хотите использовать библиотеку Globalize, такую ​​как совет @StephenMuecke, вы можете установить значения по умолчанию для jquery datepicker, подобные этому, в каком-либо сценарии инициализации или просто в заголовке документа:

$.datepicker.regional['fr'] = {
    clearText: 'Effacer', clearStatus: '',
    closeText: 'Fermer', closeStatus: 'Fermer sans modifier',
    prevText: '&lt;Préc', prevStatus: 'Voir le mois précédent',
    nextText: 'Suiv&gt;', nextStatus: 'Voir le mois suivant',
    currentText: 'Courant', currentStatus: 'Voir le mois courant',
    monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
    'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
    monthNamesShort: ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun',
    'Jul', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc'],
    monthStatus: 'Voir un autre mois', yearStatus: 'Voir un autre année',
    weekHeader: 'Sm', weekStatus: '',
    dayNames: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
    dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
    dayNamesMin: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'],
    dayStatus: 'Utiliser DD comme premier jour de la semaine', dateStatus: 'Choisir le DD, MM d',
    dateFormat: 'dd/mm/yy', firstDay: 0,
    initStatus: 'Choisir la date', isRTL: false
};
$.datepicker.setDefaults($.datepicker.regional['fr']);
person teo van kot    schedule 10.03.2015
comment
Спасибо! Я уже использую такой скрипт, см. мою правку в первом вопросе. - person clement; 10.03.2015
comment
хорошо =) это лучшее, что можно было бы сделать без Globalize, я полагаю. - person teo van kot; 10.03.2015

Это происходит потому, что ваш браузер не настроен для форматирования даты в соответствии с французским форматом: дд/мм/гггг.

Пожалуйста, скажите, что ваш браузер должен быть французским

 $.datepicker.setDefaults( $.datepicker.regional[ "fr" ] );

Кроме того, вам может понадобиться использовать помощника EditorFor вместо TextBoxFor, потому что EditorFor умнее, чем TextBoxFor.

   @Html.EditorFor(model=>model.dateAudit)

Примечание: для создания этого помощника вам может понадобиться редактор и шаблоны отображения.

person Bellash    schedule 10.03.2015
comment
спасибо за ваш ответ, это имеет смысл, но я уже сделал datepicker.setDefaults(datepicker. Regional['fr']); в сценарии инициализации (см. мой первый отредактированный пост) - person clement; 10.03.2015

Я попросил удалить проверку полей даты, потому что не хотел использовать сторонний модуль глобализации из-за совместимости браузера (поддержка браузера для модуля глобализации)

Я видел дрянное, но работающее решение в stackoverflow: ASP.NET MVC 4 избегает генерации data-val-date для datetime :

$.validator.addMethod('date', function (value, element) {
            return true; // since MVC data-val-date is put on EVERY vm date property. Default implementation does not allow for multiple cultures...
        });

Я жду более приятного решения, но это мое временное решение...

person clement    schedule 10.03.2015