Search code examples
javascriptjquerytwitter-bootstrapbootstrap-datetimepicker

How to set closest available date?


Main question: How to set closest available date?

Hi all, i'm using bootstrap-datetimepicker.

I've disabled some days from calendar and sometimes current date in range. So it disables successfully but I want to preset default date into the input value, if I use defaultDate: 'moment' it sets current date (which is disabled).

How to set closest available date?

Does exist any lifehack to resolve it? Or should I make it manually?

This is how it works now:

var $datesDisabled = [];
$.each($dates, function (key, value) {
    $datesDisabled.push(moment(value))
});

// PARAMS TO DATETIMEPICKER
var $params = {
    locale: 'en',
    format: 'DD/MM/YYYY',
    disabledDates: $datesDisabled,
};

// CHECK IF CURRENT DATE IS IN DISABLED ARRAY
if ($.inArray(moment().format('MM/DD/YYYY'), $dates) === -1) {
    // IF NOT PRESET CURRENT DATE
    $params.defaultDate = 'moment';
} else {
    // DO NOT PRESET
    $params.useCurrent = false;
}

$('.datetimepicker').datetimepicker($params);

Solution

  • According to the library documentation, you're not supposed to use defaultDate: 'moment'. They do mention the following:

    Accepts: date, moment, string

    But it means you can provide a Date object, a moment() object or a date string. The string "moment" is none of those, so it probably defaults to today.

    However, you can configure the defaultDate like this:

    // Using a date string
    $('#my-date-picker').datetimepicker({
      defaultDate: '2016-08-20'
    });
    
    // Using a Date object
    $('#my-date-picker').datetimepicker({
      defaultDate: new Date('2016-08-20')
    });
    
    // Using a moment.js object
    $('#my-date-picker').datetimepicker({
      defaultDate: moment('2016-08-20')
    });
    

    But if you want to have the defaultDate the closest date according to your disabled dates, you'll have to calculate it by yourself. For such a functionality you could create a recursive function that recalls itself with the given date minus or plus 1 until it finds one that is not disabled.

    For example:

    var disabled = [
      new Date('2016-01-03'),
      new Date('2016-01-04'),
      new Date('2016-01-05'),
      new Date('2016-01-08')
    ];
    
    function getClosest(date, disabled, direction) {
      if(!containsDate(disabled, date)) {
        return date;
      } else {
        var prev = getClosest(date.clone().add(direction || -1, 'days'), disabled, direction || -1),
            next = getClosest(date.clone().add(direction || 1, 'days'), disabled, direction || 1);
        if (Math.abs(date.diff(prev, 'days')) > Math.abs(date.diff(next, 'days'))) {
          return next;
        } else {
          return prev;
        }
      }
    }
    
    function containsDate(dates, given) {
      return dates.some(function(date) {
        return given.isSame(date, 'day');
      });
    }
    
    console.log(getClosest(moment('2016-01-02'), disabled).toDate());
    console.log(getClosest(moment('2016-01-03'), disabled).toDate());
    console.log(getClosest(moment('2016-01-04'), disabled).toDate());
    console.log(getClosest(moment('2016-01-05'), disabled).toDate());
    console.log(getClosest(moment('2016-01-06'), disabled).toDate());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js"></script>