it-swarm.com.ru

Выбор диапазона дат на jquery ui datepicker

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

Смотрите мою скрипку здесь: http://jsfiddle.net/kVsbq/4/

JS

$(".datepicker").datepicker({
    minDate: 0,
    numberOfMonths: [12, 1],
    beforeShowDay: function (date) {
        var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
        var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
        return [true, date1 && ((date.getTime() == date1.getTime()) || (date2 && date >= date1 && date <= date2)) ? "dp-highlight" : ""];
    },
    onSelect: function (dateText, inst) {
        var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
        var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
        if (!date1 || date2) {
            $("#input1").val(dateText);
            $("#input2").val("");
            $(this).datepicker();
        } else {
            $("#input2").val(dateText);
            $(this).datepicker();
        }
    }
});

То, что я хочу сделать, - это селектор диапазона, подобный этому: http://jsfiddle.net/D3wLX/1/

Если вы выбираете более раннюю дату, то более ранняя дата автоматически становится первой датой в диапазоне, а средние даты подсвечиваются. Прямо сейчас в моем исходном решении jquery ui он просто поместит более раннюю дату во второй вход и не выделит промежуточные даты.

12
Mcestone

Я нашел ответ здесь:

http://www.benknowscode.com/2012/11/selecting-ranges-jquery-ui-datepicker.html

Отличный учебник

$.datepicker._defaults.onAfterUpdate = null;
var datepicker__updateDatepicker = $.datepicker._updateDatepicker;
$.datepicker._updateDatepicker = function( inst ) {
   datepicker__updateDatepicker.call( this, inst );
   var onAfterUpdate = this._get(inst, 'onAfterUpdate');
   if (onAfterUpdate)
      onAfterUpdate.apply((inst.input ? inst.input[0] : null),
         [(inst.input ? inst.input.val() : ''), inst]);
}
$(function() {
   var cur = -1, prv = -1;
   $('#jrange div')
      .datepicker({
            //numberOfMonths: 3,
            changeMonth: true,
            changeYear: true,
            showButtonPanel: true,
            beforeShowDay: function ( date ) {
                  return [true, ( (date.getTime() >= Math.min(prv, cur) && date.getTime() <= Math.max(prv, cur)) ? 'date-range-selected' : '')];
               },
            onSelect: function ( dateText, inst ) {
                  var d1, d2;
                  prv = cur;
                  cur = (new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)).getTime();
                  if ( prv == -1 || prv == cur ) {
                     prv = cur;
                     $('#jrange input').val( dateText );
                  } else {
                     d1 = $.datepicker.formatDate( 'mm/dd/yy', new Date(Math.min(prv,cur)), {} );
                     d2 = $.datepicker.formatDate( 'mm/dd/yy', new Date(Math.max(prv,cur)), {} );
                     $('#jrange input').val( d1+' - '+d2 );
                  }
               },
            onChangeMonthYear: function ( year, month, inst ) {
                  //prv = cur = -1;
               },
            onAfterUpdate: function ( inst ) {
                  $('<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">Done</button>')
                     .appendTo($('#jrange div .ui-datepicker-buttonpane'))
                     .on('click', function () { $('#jrange div').hide(); });
               }
         })
      .position({
            my: 'left top',
            at: 'left bottom',
            of: $('#jrange input')
         })
      .hide();
   $('#jrange input').on('focus', function (e) {
         var v = this.value,
             d;
         try {
            if ( v.indexOf(' - ') > -1 ) {
               d = v.split(' - ');
               prv = $.datepicker.parseDate( 'mm/dd/yy', d[0] ).getTime();
               cur = $.datepicker.parseDate( 'mm/dd/yy', d[1] ).getTime();
            } else if ( v.length > 0 ) {
               prv = cur = $.datepicker.parseDate( 'mm/dd/yy', v ).getTime();
            }
         } catch ( e ) {
            cur = prv = -1;
         }
         if ( cur > -1 )
            $('#jrange div').datepicker('setDate', new Date(cur));
         $('#jrange div').datepicker('refresh').show();
      });
});
.wrapper {
   height: 600px;
}
#jrange input {
   width: 200px;
}
#jrange div {
   font-size: 9pt;
}
.date-range-selected > .ui-state-active,
.date-range-selected > .ui-state-default {
   background: none;
   background-color: lightsteelblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="wrapper">
   <div id="jrange" class="dates">
    <input />
    <div></div>
   </div>
</div>

6
Mcestone

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

onSelect: function(dateText, inst) {
    var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
    var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
    var selectedDate = $.datepicker.parseDate($.datepicker._defaults.dateFormat, dateText);


    if (!date1 || date2) {
        $("#input1").val(dateText);
        $("#input2").val("");
        $(this).datepicker();
    } else if( selectedDate < date1 ) {
        $("#input2").val( $("#input1").val() );
        $("#input1").val( dateText );
        $(this).datepicker();
    } else {
        $("#input2").val(dateText);
        $(this).datepicker();
    }
}

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

Вот моя раздвоенная скрипка: http://jsfiddle.net/sWbfk/

17
Jamie Layne

Чувак, твой код действительно то, что мне нужно!

И с поправкой Джейми Лэйна я решил использовать ее для создания плагина.

Вот ссылка для jsfiddle: http://jsfiddle.net/dxLRm/35/ (ссылка обновлена ​​2014/01/01)

Так как я должен показать некоторый код, вот что у меня есть:

(function ($) {
$.prototype.rangedatepicker = function (o,x,y) {
    var dp = $.datepicker,
        cl = dp.markerClassName,
        di = 'data-rdp-i',
        df = 'data-rdp-f';

    switch(o)
    {
        case 'option':
            return $(this).datepicker('option');
        case 'hide':
            return $(this).datepicker('hide');
        case 'show':
            return $(this).datepicker('show');
        case 'getInitialDate':
            return dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(di)||'');
        case 'getFinalDate':
            return dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(df)||'');
        case 'getRange':
            var ini=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(di)||''),
                fin=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(df)||'');
            return (!ini&&!fin)?null:[ini,fin];
        case 'getNumDays':
            var ini=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(di)||''),
                fin=dp.parseDate($(this).eq(0).datepicker('option','dateFormat'),$(this).eq(0).attr(df)||'');
            return (ini+0==0||fin+0==0)?0:Math.round((fin-ini)/86400000)+1;
        case 'removeRange':
            return $(this).attr(di,'').attr(df,'').datepicker('setDate',null);
        case 'destroy':
            return $(this).removeAttr(di).removeAttr(df).datepicker('destroy');
        case 'serialize':
            return this[0].id+'_initial='+this[0].getAttribute(di)+'&'+this[0].id+'_final='+this[0].getAttribute(df);
        default:
        var defaults={
            allowSelectOneDay: false,
            alwaysSetDateToFirstDay: true,
            rangeEnabled: true,
            rangeClass: 'ui-state-default ui-state-active'//'dp-highlight'
        };
            o = $.extend({}, defaults, $.datepicker._defaults, o);
        return $(this).each(function () {
            if (!$.datepicker) return;
            var t = this,
                hd = !! ((' ' + t.className + ' ').indexOf(' ' + cl + ' ') + 1);
            $(t).datepicker($.extend({}, o, {
                beforeShowDay: function (d) {
                    if (o.rangeEnabled) {
                        var d1 = dp.parseDate(o.dateFormat, t.getAttribute(di) || ''),
                            d2 = dp.parseDate(o.dateFormat, t.getAttribute(df) || ''),
                            y = (function (d) {
                                try {
                                    return o.beforeShowDay.call(t, d);
                                } catch (e) {}
                            })(d) || [true, '', null],
                            x = ((y && y[0] !== false) || !y) && d1 && ((d.getTime() == d1.getTime()) || (d2 && d >= d1 && d <= d2));
                        return (!d1||!d2)?y||[true,'',null]:[y[0]&&x, (x ? o.rangeClass || defaults.rangeClass : '') + (y[1] ? ' ' + y[1] : ''), y[2]];
                    } else {
                        return (function (d) {
                            try {
                                return o.beforeShowDay.call(t, d);
                            } catch (e) {}
                        })(d) || [true, '', null];
                    }
                },
                onSelect: function (dt, x) {
                    if (o.rangeEnabled) {
                        var i = t.getAttribute(di) || '',
                            f = t.getAttribute(df) || '',
                            d1 = dp.parseDate(o.dateFormat, i),
                            d2 = dp.parseDate(o.dateFormat, f),
                            s = dp.parseDate(o.dateFormat, dt);
                        if ((dt == i && dt == f) || (!o.allowSelectOneDay && ((dt == i && !f) || (dt == f && !i)))) {
                            t.removeAttribute(di);
                            t.removeAttribute(df);
                            $(t).datepicker('setDate', null);
                        } else if (!d1 || d2) {
                            t.setAttribute(di, dt);
                            t.removeAttribute(df);
                            o.alwaysSetDateToFirstDay && $(t).datepicker('setDate', s);
                        } else if (s < d1) {
                            t.setAttribute(df, i);
                            t.setAttribute(di, dt);
                            o.alwaysSetDateToFirstDay && $(t).datepicker('setDate', s);
                        } else {
                            t.setAttribute(df, dt);
                            o.alwaysSetDateToFirstDay && $(t).datepicker('setDate', d1);
                        }
                    } else {
                        t.removeAttribute(di);
                        t.removeAttribute(df);
                        $(t).datepicker('setDate', dp.parseDate(o.dateFormat, dt));
                    }

                    try {
                        if($(t).datepicker('getDate'))o.onSelect.call(t, dt, x);
                    } catch (e) {}
                }
            }));
        });
    }
};
})(window.jQuery);

Вы должны получить доступ к скрипке и прочитать список вещей, которые нужно сделать!

Любая идея или кусок кода приветствуется!

1
Ismael Miguel

Я также искал способ расширить плагин DatePicker jQuery для использования стиля Bootstrap и наткнулся на этот маленький драгоценный камень:

Bootstrap-Date Range Picker от Dan Grossman показывает несколько живых примеров с рабочим кодом. 

Вот и проект GitHub .

Наконец, вот скриншот простоты и мощности дизайна:

 screenshot

1
Blairg23

Спасибо, мне нужен такой код. Вот мой код: 

<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script     src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

 <div id="Datepicker"></div>
<p>
<label><b>Checkin:</b></label> <label id="checkinDate"></label>
<label><b>Checkout:</b></label> <label id="checkoutDate"></label>
</p>

/** Display Checkin Datepicker and Checkout DatePicker */
<script>
datePicker();
function datePicker(){
   $(document).ready(function(){
      $( "#Datepicker" ).datepicker({
         dateFormat: "MM d, yy",
     minDate: 0,
     maxDate: "+3M +0D", 
         beforeShowDay: dateRange,
     onSelect: DRonSelect
      });
   });
}

function dateRange(date){
   var date1 = $.datepicker.parseDate("MM d, yy", $("#checkinDate").text());
   var date2 = $.datepicker.parseDate("MM d, yy", $("#checkoutDate").text());
   var isHighlight = date1 && ((date.getTime() == date1.getTime()) || (date2 && date >= date1 && date <= date2));
      $(document).ready(function(){
  // $("td.dp-highlight").text("Y");

});
   return [true, isHighlight ? "dp-highlight" : ""];
}

function DRonSelect(dateText, inst) {
   var date1 = $.datepicker.parseDate("MM d, yy", $("#checkinDate").text());
   var date2 = $.datepicker.parseDate("MM d, yy", $("#checkoutDate").text());
      if (!date1 || date2) {
         $("#checkinDate").text(dateText);
     $("#checkoutDate").text("");
         $("#Datepicker").datepicker();
      } 
      else {
         if ( $.datepicker.parseDate("MM d, yy", $("#checkinDate").text()) >= 
$.datepicker.parseDate("MM d, yy", dateText)) {
            $("#checkinDate").text(dateText);
            $("#checkoutDate").text("");
            $("#Datepicker").datepicker();
         }
         else {
        $("#checkoutDate").text(dateText);
            $("#Datepicker").datepicker();
         }
      }   
}
</script>

Мой код является примером кода, полученного от других, но отличается выбором даты, диапазоном дат и основными моментами. Я создал и сохранил код в JSFIDDLE

https://jsfiddle.net/kk585b4g/

1
Marvin

Сам искал подборщика дат, нашел эту страницу. Я попробовал большинство идей, предложенных и даже продемонстрированных здесь, и превратил все это в простое в использовании и интегрируемое расширение: https://github.com/BuroRaDer/DateRangePicker . Попробуйте демо-страницу, чтобы увидеть, как это работает. Я думаю, я мог бы превратить его в настоящее расширение jQuery, но сейчас я доволен тем, как это работает.

Живые демки: 

Оба сайта являются сайтами Drupal, использующими модуль «Календарь доступности», в который он был интегрирован.

0
fietserwin

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

Вот скрипка: http://jsfiddle.net/boson/pjffdtz2/

Сложная часть, похоже, заключается в том, что DatePicker обрабатывает несколько входов, когда они не встроены. Datepicker не будет легко обрабатывать два ввода, если вы хотите открыть datepicker в фокусе - определенно был «трюк». Если вы связываете указатель даты со скрытым вводом (отображение: отсутствует), создаете этот скрытый ввод перед видимыми входами, а затем пусть ваши видимые входы отображают указатель даты в событии щелчка, все хорошо.

Поэтому я взял исходный ответ и внес несколько небольших изменений:

  • В html создайте скрытый ввод, связанный с указателем даты. Перечислите это перед видимыми входами.
  • В html используйте событие click видимых входов, чтобы показать средство выбора даты, связанное со скрытым вводом.
  • В Javascript datepicker onSelect временно переведите указатель даты во встроенный режим до тех пор, пока не будут нажаты обе даты. Это позволяет щелкать несколько дат до закрытия средства выбора даты (диапазон дат «До» и «От») - это по существу превращает средство выбора даты в средство выбора даты с несколькими щелчками мыши.
  • В DatePicker onClose отключите встроенный режим. Это позволяет кому-то нажимать на поля ввода, чтобы снова открыть средство выбора даты. 
  • В beforeShow переместите указатель даты на несколько пикселей вниз, чтобы увидеть поля ввода и указатель даты.

Вот код:

$(function() {
  $(".rangepicker").datepicker({
    minDate: 0,
    numberOfMonths: [2, 1],
    beforeShow: function (input, inst) {
      var rect = input.getBoundingClientRect();
      setTimeout(function () {
	      inst.dpDiv.css({ top: rect.top + 40, left: rect.left + 0 });
      }, 0);
    },
    beforeShowDay: function(date) {
      var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
      var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
      var isHighlight =
         date1 && ((date.getTime() == date1.getTime()) || (date2 && date >= date1 && date <= date2));
      return [true, isHighlight ? "dp-highlight" : ""];
    },
    onSelect: function(dateText, inst) {
      var date1 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input1").val());
      var date2 = $.datepicker.parseDate($.datepicker._defaults.dateFormat, $("#input2").val());
      var selectedDate = $.datepicker.parseDate($.datepicker._defaults.dateFormat, dateText);

      if (!date1 || date2) {
        $("#input1").val(dateText);  
        $("#input2").val("");        
      } else if (selectedDate < date1) {
          $("#input2").val($("#input1").val()); 
          $("#input1").val(dateText);  
      } else {
          $("#input2").val(dateText);  
      }
      $(this).data('datepicker').inline = true;           
      $(this).datepicker();
    },
    onClose: function() {
      // Since we went inline as soon as the date input was clicked
      // (to leave the datepicker up for both dates selection),
      // turn inline back off again so date input click will once again
      // display the datepicker
      $(this).data('datepicker').inline = false;
    }
  });
});
.dp-highlight .ui-state-default {
          background: #484;
          color: #FFF;
        }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<input type="text" id="input1_1" class="rangepicker" style="display: none">
<p>
    Dates:
    <label><b>To:</b></label>
    <input type="text" id="input1" onclick="$('.rangepicker').datepicker('show');">
    <label><b>From:</b></label>
    <input type="text" id="input2" onclick="$('.rangepicker').datepicker('show');">
    <button id="done">Done</button>
</p>

Многое осталось улучшить. Требуется лучшая проверка ввода. Особенно хотелось бы, чтобы кнопка DatePicker «Done» работала во встроенном режиме, но DatePicker не был разработан для этого сценария (конечно, было бы неплохо иметь настраиваемый флаг кнопки Done в DatePicker). Итак, на данный момент у меня есть кнопка «Готово» рядом с полями ввода, которая на самом деле ничего не делает (кроме того, чтобы побудить пользователя убрать фокус с выбора даты, чтобы закрыть средство выбора даты).

0
boson