2016-09-23 3 views
0

Я использую плагин проверки JQuery Jörn Zaefferer рядом с jQuery UI datepicker. Я создал набор настраиваемых правил для проверки того, что дата начала до даты окончания.Проверка диапазона дат с помощью jQuery UI datepicker: порядок событий

Проблема заключается в том, что когда у меня есть недопустимый диапазон и используйте пользовательский интерфейс datepicker для изменения даты, чтобы сделать допустимый диапазон действительным, я вижу, что проверка выполняется со старыми значениями (и, таким образом, недействительными полями) до активировать обратный вызов onSelect для datepicker.

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

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

Here's the fiddle

Чтобы воспроизвести проблему, введите 15-го числа данного месяца в начале, а 7-го того же месяца, в конце концов. Нажмите поле «Пуск», а затем нажмите или вкладку, чтобы активировать проверку. Поля корректно недействительны. Теперь щелкните поле «Пуск» и выберите 1-е число того же месяца. Обратите внимание на то, что выводится в этот момент на консоли.

Код для ссылки:

HTML

<form id="daterange-form"> 
    <div class="form-group"> 
     <label for="startDate">Start Date</label> 
     <input type="text" id="startDate" name="startDate" class="validDate form-control" /> 
    </div> 

    <div class="form-group"> 
     <label for="endDate">End Date</label> 
     <input type="text" id="endDate" name="endDate" class="validDate form-control" /> 
    </div> 
    <button type="submit" class="btn">Submit</button> 
</form> 

JavaScript

// Custom Rules 
$.validator.addMethod('dateBefore', function(value, element, params) { 
    // if end date is valid, validate it as well 
    console.log('dateBefore', value, element, params) 
    var end = $(params); 
    if (!end.data('validation.running')) { 
    $(element).data('validation.running', true); 
    // The validator internally keeps track of which element is being validated currently. This ensures that validating 'end' will not trample 'start' 
    // see http://stackoverflow.com/questions/22107742/jquery-validation-date-range-issue 
    setTimeout($.proxy(
     function() { 
     this.element(end); 
     }, this), 0); 
    // Ensure clearing the 'flag' happens after the validation of 'end' to prevent endless looping 
    setTimeout(function(){ 
     $(element).data('validation.running', false); 
    }, 0); 
    } 
    return this.optional(element) || this.optional(end[0]) || new Date(value) < new Date(end.val());  
}, 'Must be before its end date'); 

$.validator.addMethod('dateAfter', function(value, element, params) { 
    // if start date is valid, validate it as well 
    console.log('dateAfter', value, element, params) 
    var start = $(params); 
    if (!start.data('validation.running')) { 
    $(element).data('validation.running', true); 
    // The validator internally keeps track of which element is being validated currently. This ensures that validating 'end' will not trample 'start' 
    // see http://stackoverflow.com/questions/22107742/jquery-validation-date-range-issue 
    setTimeout($.proxy(
     function() { 
     this.element(start); 
     }, this), 0); 
    // Ensure clearing the 'flag' happens after the validation of 'end' to prevent endless looping 
    setTimeout(function() { 
     $(element).data('validation.running', false); 
    }, 0); 
    } 
    return this.optional(element) || this.optional(start[0]) || new Date(value) > new Date($(params).val());  
}, 'Must be after its start date'); 


// Code setting up datepicker and validation 
$('#startDate, #endDate').datepicker({ 
    onSelect: function(dateText, inst) { 
    console.log('onSelect', dateText, inst) 
    } 
}); 
$('#daterange-form').validate({ 
    debug: true, 
    rules: { 
    startDate: {dateBefore: '#endDate'}, 
    endDate: {dateAfter: '#startDate'} 
    } 
}); 

Боковая примечание: таймауты и прокси-вызовы в правила, потому что эта версия библиотека внутренне предполагает последовательную проверку. Если вы попытаетесь проверить другое поле в середине правила, произойдет Bad Things. Код семафора validation.running предназначен для предотвращения бесконечного цикла.

+0

Я хотел бы отметить, что в нашем коде, мы в настоящее время используют этот фокус-то размытости обходной путь http://stackoverflow.com/ а/19838943/749227. В основном мне любопытно, почему датпикер, похоже, вызывает какое-либо событие, которое требуется для проверки, до фактического обновления значения, и как обойти его, не задумываясь о том, чтобы скопировать-вставить одно и то же обходное решение каждый раз, когда у нас есть допустимый диапазон дат. – jinglesthula

ответ

1

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

Заказ должен/не имеет значения, поскольку, как вы знаете, это только инициализация, а не реализация.

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

дата-подборщик действительно обновляет значение input, однако проверка не срабатывает, потому что это не является нормальным событием плагиной проверки ожидают. Проверка выполняется только по событиям submit, keyup и focusout, ни одна из которых не возникает при использовании .datepicker().

Таким образом, вы можете программно заставить тест проверки с помощью the .valid() method всякий раз, когда вы хотите ...

$('#startDate, #endDate').datepicker({ 
    onSelect: function(dateText, inst) { 
     $(this).valid(); 
    } 
}); 

DEMO: jsfiddle.net/nkvpsumq/2/

.valid() могут быть присоединены к индивидуальным input, select, textarea, или весь form. При подключении к селектору, который содержит более одного объекта, вы должны заключить этот метод с помощью jQuery .each(). В вашем случае .each() не требуется, потому что вы уже программно повторно запускаете проверку в противоположном поле, используя this.element() в своих пользовательских правилах. Теперь, когда вы знаете о запуске метода .valid() через событие .datepicker(), вы можете захотеть реорганизовать остальную часть своего кода.

+0

К кому это может относиться. Если вы столкнетесь с этим, и вы думаете о расширении datepicker, поэтому метод '_selectDate' может выполнять вызов' .valid() ', см. Мой комментарий к этому ответу http://stackoverflow.com/a/13763473/749227 , По-видимому, датпикер немного отличается от своих братьев и сестер. – jinglesthula

0

Вот код, который я использовал, чтобы решить проблему и сохранить ее СУХОЙ.

$.datepicker._selectDate_super = $.datepicker._selectDate; 
$.datepicker._selectDate = function(id, dateStr) { 
    $.datepicker._selectDate_super(id, dateStr); 
    $(id).valid(); 
};  

(или, если вы предпочитаете ES6 и АСИ;)

$.datepicker._selectDate_super = $.datepicker._selectDate 
$.datepicker._selectDate = (id, dateStr) => { 
    $.datepicker._selectDate_super(id, dateStr) 
    $(id).valid() 
} 
Смежные вопросы