Home > forms > Changing to date field based on from date using javascript

Changing to date field based on from date using javascript

September 24Hits:2
Advertisement

I have a form written using Drupal's FAPI (Drupal v7.15). The form includes two date fields - a from date and a to date. I've installed the Date module and both fields are both set-up to use the 'date_popup' widget.

Now I want to make the to date automatically change when the from date is updated by the user. Eg if the user sets the from date to 1st Nov 2012, I want the to date to automatically change to match the from date. Ideally I would also like the date picker to disable all options earlier than this date. This is the same behaviour you see on many travel sites, such as expedia.com.

I can't find a good example of how to add the Javascript to do this. I can only see AJAX examples, and it seems unnecessary to make a round trip to the server to do this - the browser has all the info it needs to do so client side.

Answers

If I understand you right it should be as simple as dropping something like this into a JS file included in the page:

(function($) {
  Drupal.behaviors.myModule = {
    attach: function(context, settings) {
      $('#edit-from-date', context).change(function() {
        $('#edit-to-date', context).val($(this).val());
      });
    }
  }
})(jQuery);

Disabling certain dates is a bit more complicated but there's an example here that should point you in the right direction.

Here's the complete solution. The 'to date' is updated to the 'from date' plus one week and dates in its datepicker are disabled for dates equal to or earlier to the 'from date'. The form fields are created with Drupal's Forms API.

First the PHP code

$default_from = date('Y-m-d 00:00:00', strtotime(date('Y-m-d')." +1 month"));
$form['dates']['from_date'] = array(
    '#type' => 'date',
    '#title' => t('Ingreso'),
    '#type' => 'date_popup',
    '#date_year_range' => '-0:+2',
    '#date_format' => 'd/m/Y',
    '#default_value' => $default_from,
    '#datepicker_options' => array('minDate' => 'today'),
    '#required' => TRUE,
);

$form['dates']['to_date'] = array(
    '#type' => 'date',
    '#title' => t('Salida'),
    '#type' => 'date_popup',
    '#date_year_range' => '-0:+2',
    '#date_format' => 'd/m/Y',
    '#default_value' => date('Y-m-d 00:00:00', strtotime($default_from." +1 week")),
    '#datepicker_options' => array('minDate' => date('d/m/Y', strtotime($default_from." +1 day"))),
    '#required' => TRUE,
);

Then the Javascript

(function($) {
Drupal.behaviors.viajes = {
    attach: function(context, settings) {
        $('#edit-from-date-datepicker-popup-0', context).change(function() {

            //change min to-date to from-date plus one day
            if ($("#edit-to-date-datepicker-popup-0" ).hasClass('hasDatepicker')) {
                $("#edit-to-date-datepicker-popup-0" ).datepicker( "option", "minDate", addDays($(this).val(),1) ); //this method if to datepicker already initialised
            } else {
                Drupal.settings.datePopup['edit-to-date-datepicker-popup-0']['settings']['minDate'] = addDays($(this).val(),1); //this method if to datepicker has never been used
            }

            //change to-date to from-date plus one week
            $('#edit-to-date-datepicker-popup-0', context).val( addDays($(this).val(),7) );

        });

        //takes date string in format dd/mm/yyyy and returns date plus 'days' in the same format
        function addDays(dateStr, days) {
            //convert to date obejct
            var dateArray = dateStr.split('/');
            var date = new Date(dateArray[2], dateArray[1]-1, dateArray[0]);

            //add days
            date.setDate(date.getDate() + days);

            //convert back to correct string format and return
            return addZero(date.getDate()) + '/' + addZero(date.getMonth()+1) + '/' + date.getFullYear();
        }

        //add leading zero if number is 9 or less
        function addZero(number) {
            if (number <= 9) {
                return '0'+number;
            } else {
                return number;
            }
        }
    }
}
})(jQuery);

This is a modified version of adamf321's script. The differences are:

  • Format independent, uses the format set in Drupal instead of mm/dd/yy
  • Preserves the time difference to 'to date' when changing the 'from date'

You can change the fromDateId and toDateId to match your input field id's.

(function($) {
  Drupal.behaviors.myModule = {
    attach: function(context, settings) {
      var fromDateId = 'edit-from-date-datepicker-popup-0';
      var toDateId = 'edit-to-date-datepicker-popup-0';
      var $fromDate = $('#'+fromDateId, context);
      var $toDate = $('#'+toDateId, context);
      var currentfromDate = $fromDate.val();
      $fromDate.change(function() {
        var dateFormat = $fromDate.datepicker('option','dateFormat');

        //change min to-date to from-date plus one day
        if ($toDate.hasClass('hasDatepicker')) {
          $toDate.datepicker( "option", "minDate", addDays(dateFormat,$(this).val(),1)); //this method if to datepicker already initialised
        } else {
          Drupal.settings.datePopup[toDateId]['settings']['minDate'] = addDays(dateFormat,$(this).val(),1); //this method if to datepicker has never been used
        }

        //move toDate the same amount as fromDate has moved
        var daysShifted = dateStrDiff(dateFormat, currentfromDate, $(this).val());
        $toDate.val(addDays(dateFormat,$toDate.val(), daysShifted));
        currentfromDate = $fromDate.val();
      });

      //takes date string in given format (e.g. 'dd-mm-yy') and returns date plus 'days' in the same format
      function addDays(format, dateStr, days) {
        //convert to date object
        var date = getDate(format, dateStr);

        //add days
        date.setDate(date.getDate() + days);

        //convert back to correct string format and return
        return jQuery.datepicker.formatDate(format, date);
      }

      function getDate(format, dateStr) {
        return $.datepicker.parseDate(format, dateStr);
      }

      function dateStrDiff(format, dateStr1, dateStr2) {
        var date1 = getDate(format, dateStr1);
        var date2 = getDate(format, dateStr2);
        return dateDiffInDays(date1, date2);
      }

      // See http://stackoverflow.com/questions/3224834/get-difference-between-2-dates-in-javascript
      // a and b are javascript Date objects
      function dateDiffInDays(a, b) {
        var _MS_PER_DAY = 1000 * 60 * 60 * 24;
        // Discard the time and time-zone information.
        var utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
        var utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());

        return Math.floor((utc2 - utc1) / _MS_PER_DAY);
      }

    }
  }
})(jQuery);

Related Articles

Copyright (C) 2018 ceus-now.com, All Rights Reserved. webmaster#ceus-now.com 14 q. 0.726 s.