【问题标题】:Date range validation with jQuery UI datepicker: order of events使用 jQuery UI datepicker 验证日期范围:事件的顺序
【发布时间】:2017-02-01 21:32:49
【问题描述】:

我正在使用 Jörn Zaefferer 的 jQuery 验证插件以及 jQuery UI 日期选择器。我创建了一组自定义规则来验证开始日期是否早于结束日期。

我遇到的问题是,当我的范围无效并使用 datepicker UI 更改日期以使范围有效时,我看到验证在为日期选择器触发 onSelect 回调。

我希望日期选择器会在用户选择时更新输入的值,并且任何验证代码都会在发生这种情况时运行并查看新值。但这似乎没有发生。

我尝试在初始化验证之前初始化日期选择器,希望事件的连接顺序会有所不同,但您可以看到它没有帮助。

Here's the fiddle

要重现问题,请在开头输入给定月份的 15 号,最后输入同一个月的 7 号。单击开始字段,然后单击或跳出以触发验证。字段正确无效。现在单击开始字段并选择同月的第一天。注意此时控制台上的输出。

代码,供参考:

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'}
  }
});

旁注:规则中的超时和代理调用是因为此版本的库在内部假定串行验证。如果您尝试在规则中间验证另一个字段,就会发生坏事。 validation.running 信号量代码是为了防止无限循环。

【问题讨论】:

  • 我应该注意到,在我们的代码中,我们目前正在使用这种先聚焦后模糊的解决方法stackoverflow.com/a/19838943/749227。大多数情况下,我很好奇为什么日期选择器似乎会导致在实际更新值之前触发验证正在寻找的任何事件,以及如何绕过它而不必记住每次我们都有复制粘贴相同的解决方法一个经过验证的日期范围。

标签: javascript jquery jquery-ui datepicker jquery-validate


【解决方案1】:

我尝试在初始化验证之前初始化日期选择器,希望事件的连接顺序会有所不同,但您可以看到它没有帮助。

顺序应该/不重要,因为如您所知,这只是初始化,而不是实现。

我希望日期选择器会在用户选择时更新输入的值,并且任何验证代码都会在发生这种情况时运行并查看新值。但这似乎没有发生。

日期选择器确实更新了input 值,但是不会触发验证,因为这不是验证插件所期望的正常事件。验证仅在submitkeyupfocusout 事件上触发,使用.datepicker() 时不会发生。

因此,您可以随时使用the .valid() method 以编程方式强制进行验证测试...

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

演示:jsfiddle.net/nkvpsumq/2/

.valid() 可以附加到单个 inputselecttextarea 或整个 form。当附加到包含多个对象的选择器时,您必须使用 jQuery .each() 封装此方法。在您的情况下,不需要.each(),因为您已经在自定义规则中使用this.element() 以编程方式重新触发对立字段的验证。既然您知道如何通过 .datepicker() 事件触发 .valid() 方法,您可能希望稍微重构一下其余代码。

【讨论】:

  • 它可能关注的对象。如果您遇到这种情况并且您正在考虑扩展日期选择器以便_selectDate 方法可以执行.valid() 调用,请参阅我对这个答案stackoverflow.com/a/13763473/749227 的评论。显然 datepicker 与它的兄弟姐妹相比有点特别。
【解决方案2】:

这是我最终用来解决问题并保持 DRY 的代码。

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

(或者如果你更喜欢 es6 和 ASI ;)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多