Не мога да проверявам полето за дата и час във формуляра

Използвам този обект:

[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! Контролът на формата е CSS клас, приложен към входа, за да го стилизира с twitter bootstrap. Не мисля, че прави някои промени за валидиране. Току-що се опитах да премахна този клас, все още има проблем.   -  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 UI) може да е просто

$.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
FYI Този първи метод има ОСНОВЕН недостатък. Създавате нова дата (текуща дата) с var date = new Date();. Ако Хелоуин (да днес), тогава тази дата става 31.10.2018 г. Да приемем, че валидирате на 01.06.2018 г. Ако замените първо годината (date.setFullYear(year);) и след това месеца (юни) ПРЕДИ да зададете деня, получавате 6/31/2018. Така че преди дори да стигнете до реда, който гласи date.setDate(day); вече имаш невалидна дата. Можете да опитате първо да зададете датата, но ако потвърждавате дата 31 и случайно е февруари, вие също сте нагоре. Този метод не работи - person Brian Lorraine; 31.10.2018
comment
Може би преди да направите setmonth,setfullyear,setdate на обекта date, първо задайте датата и месеца на 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