I wanted to be able to prevent users from selecting a date in the past from the datepicker popup. After some research into the jQuery datepicker plugin I discovered that you can pass the option "minDate" at the time the popup is called. I tested this by hard-coding an addition to the $settings array in date_popup.module. But it would be better if we added a selector to the date_popup element to allow any additional options to be passed through. I suggest:

date_popup.module line 277:

  if (is_array($element['#datepicker_options']) && !empty($element['#datepicker_options'])){
	$settings += $element['#datepicker_options'];
  }

It could then be invoked when you define a form, for example:

	 '#datepicker_options' => array('minDate' => 'today'),

What do you think?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Hubert_r’s picture

+1 Great idea!

mmilo’s picture

This would be -extremely- helpful if we want to customize the datepicker.

A good point of reference would be #625264: Improvements to date_popup module.

maykbrito’s picture

Tks bro! works great!

=)

maykbrito’s picture

How about 'onSelect' option?? My js was like this:

$('#edit-stigma-start').datepicker(
        {
            dateFormat: 'd MM yy',
            timeFormat: 'h:mm',
            hideIfNoPrevNext: false,
            changeMonth: true,
            changeYear: true,
            onSelect: function(selectedDate)
            {
                var instance = $(this).data("datepicker");
                var date = $.datepicker.parseDate(instance.settings.dateFormat || $.datepicker._defaults.dateFormat, selectedDate, instance.settings);

                $('#edit-stigma-end').datepicker("option", "minDate", date);
                $('#edit-stigma-end').val(selectedDate);
            }
        }
    );
just_like_good_vibes’s picture

hello and thanks for the tip !

just to be sure, you meant to patch the file "date_popup.module",
in function "date_popup_process_date_part" and just after the creation of the settings array, right?

i also changed a little bit the added code to :

if (array_key_exists('#datepicker_options',$element) && is_array($element['#datepicker_options']) && !empty($element['#datepicker_options'])){
    $settings += $element['#datepicker_options'];
  }

cheers

kristiaanvandeneynde’s picture

Status: Active » Needs review
FileSize
2.84 KB

Edit:
Never mind, there's a mixup in this one.
Look at the next comment...

kristiaanvandeneynde’s picture

Added a patch that:

  • adds #datepicker_options defaults to hook_element_info()
  • updates the docs for this change
  • allows an override of all jQuery datepicker settings

Please test and review.

kristiaanvandeneynde’s picture

Sorry for all the mix-ups, I had some user unfriendly logic in setting the defaults.
This should work even better.

KarenS’s picture

Version: 7.x-2.x-dev » 6.x-2.x-dev
Status: Needs review » Patch (to be ported)

Committed, thanks!

http://drupalcode.org/project/date.git/commit/ade4a42

Let's backport this approach to D6. Anyone want to roll a patch for D6?

jim_at_miramontes’s picture

Hmm -- I'm running v. 7.x-2.6 of date_popup, but am not able to get it to recognize the datepicker options. My form element looks like this:

	$form['target_date'] = array(
		'#type' => 'date_popup',
		'#date_label_position' => 'above',
		'#date_format' => 'F j, Y',
		'#date_year_range' => '0:+3',
		'#attributes' => array('class' => array('required')),
		'#datepicker_options' => array('minDate' => 0),
	);

The datepicker comes up and works fine, but without the minDate restriction. Does anyone have any advice? Thanks!

kristiaanvandeneynde’s picture

http://api.jqueryui.com/datepicker/#option-minDate

Is 0 even a valid setting?
Try setting it to something else and see if that works.

alexweber’s picture

@kristiaanvandeneynde, 0 is actually a valid setting, as per this Stack Overflow answer as well as my own experience.

@jim_at_miramontes, I'm using jQuery UI Datepicker 1.8.11 (via jQuery Update) and Date 7.x-2.6 and can confirm 100% that it does indeed work. I incidentally just implemented this for a project, see attached screenshots from my code and website...

Are you using an older jQuery UI version?

MasteRRR’s picture

Hello, everybody. How can I use datepicker options which needs a functions as arguments?
example: http://api.jqueryui.com/datepicker/#option-beforeShowDay

I tried to disable weekends and holidays using this solution, but can't call javascript function.

$dateformat='Y-m-d';
  $datef=date($dateformat);
  $form['choose_date'] = array(
      '#title' => t('Enabled on'),
      '#type' => 'date_popup',
      '#default_value' => $datef,
      '#date_format' => $dateformat,
      '#datepicker_options' => array(
        'minDate' => 0,
        'maxDate' => "+3w",
        'beforeShowDay' => '$',
      ),
  );

Is it possible? What should I do to solve this problem?

kristiaanvandeneynde’s picture

You can't pass functions to JavaScript from PHP because they would be passed as strings instead of reference types.

A 'very bad idea ™' workaround would be to adjust the JS that creates the datepicker and eval() the #datepicker_options keys that expect a callback.

jonhattan’s picture

@MasteRRR I managed to solve this and posted an answer on stackexchange: http://drupal.stackexchange.com/questions/58968/customize-days-that-can-...

kristiaanvandeneynde’s picture

Jonhattan's idea should work.

P.S.: I'm glad to see people are actually finding the #datepicker_options key useful :)

MasteRRR’s picture

Status: Patch (to be ported) » Needs review
FileSize
3.2 KB

Thanks @jonhattan and @Kristiaanvandeneynde, your help was very useful.
Jonhattan's idea works greatly and I applyed this approach for Drupal 6.
Also I've backported Kristiaans patch for Drupal 6, so if testing show no errors, this issue can be closed.

jim_at_miramontes’s picture

@alexweber It's working for me; I was outsmarting myself with some ajax games.

nightlife2008’s picture

I solved this problem using the HOOK_date_popup_process_alter(), which is run AFTER the element has been processed, to add the #datepicker_options array.

After adding the options, I just reprocess the element with the proper options set.

function MODULE_date_popup_process_alter(&$element, &$form_state, &$context) {
  if (isset($element['#field']['field_name'])) {
    switch ($element['#field']['field_name']) {
      case 'field_fact_periode': {
        $element['#datepicker_options'] = array(
          'minDate' => "+3D",
        );
        $element['date'] = date_popup_process_date_part($element);
      }
      break;
    }
  }
}

Works like a charm!

akalata’s picture

Thanks for the example, nightlife2008!

jimmyko’s picture

Issue summary: View changes

Is it fixed? I am finding help on applying data_popup options with jQuery function. I find something help from the comment above. But since this was already implemented the versions after 7.x-2.6. I don't know how is the progress on 6.x

If anyone confirm it is fixed. I do think this issue should be changed to closed.

zhiqiang.qiu’s picture

it looks great!

marie.pinet’s picture

Hello,

Here is a patch that allow the use of the beforeShowDay feature of datepicker.

It is for the 7.x-2.x version.

Example:

$form['date_of_newsletter'] = array(
    '#id' => 'date_of_search',
    '#type' => 'date_popup',
    '#default_value' => ...
    '#date_type' => DATE_DATETIME,
    '#date_timezone' => date_default_timezone_get(),
    '#date_format' => 'd/m/Y',
    '#date_increment' => 1,
    '#date_year_range' => '-3:0',
    '#datepicker_options' => array(
      'beforeShowDay' => 'EnableOnlyFriday',
    ),
  );

Where EnableOnlyFriday is a JS function in my custom code. The problem I had was that datepicker API require a function name and not a string of the function name.

DamienMcKenna’s picture

Version: 6.x-2.x-dev » 7.x-2.x-dev

Switching this to the D7 branch.

solideogloria’s picture

Patch #23 has been working for a several months for me, though it only addresses a single property, but it was the one I needed.

solideogloria’s picture

Status: Needs review » Reviewed & tested by the community
DamienMcKenna’s picture

The patch needs to be updated to match Drupal's coding standards (indenting), and a comment would be useful.

solideogloria’s picture

I tried the solution linked in #15, and it works:

drupal_add_js(drupal_get_path('module', 'FOO') . '/FOO.js');
(function ($) {
Drupal.behaviors.FOO = {
  attach: function (context) {
    for (var id in Drupal.settings.datePopup) {
      Drupal.settings.datePopup[id].settings.beforeShowDay = $.datepicker.noWeekends;
    }
  }
};
})(jQuery);

I think I'm willing to follow the safer path of not adding an eval statement. However, if you think otherwise, I modified the patch as stated in the previous comment.

solideogloria’s picture

Status: Reviewed & tested by the community » Needs review

I also noticed that the if block is before the switch statement. Would it be better to have it only if case 'datepicker'?

Anybody’s picture

Re @DamienMcKenna

The patch needs to be updated to match Drupal's coding standards (indenting), and a comment would be useful.

This has been done in #28, while I'm not feeling very well about the eval(). See https://www.digitalocean.com/community/tutorials/js-eval

Is there a better pattern to allow defining the function server-side and pass it to the jQuery UI element?

Otherwise I think the JS code in #28 is the better alternative.

solideogloria’s picture

Note: I still think #15 is the best way to go (see this SE answer).

However, I just did some work with a "better eval" recently. Though you cannot define a function server-side and execute it client-side without evaluating it (because it has to be executed somehow, like with eval), there are safer ways to execute it.

Never use eval()!

I ended up using something like this for my purposes:

            try {
              // Better than using eval().
              Function(jsString)();
            }
            catch (e) {
              console.error(e);
            }
            finally {
              onScriptLoaded();
            }

So for an improvement to #28, I think we could use this line instead of the line with eval():

datePopup.settings.beforeShowDay = Function(datePopup.settings.beforeShowDay);

If someone wants to consider updating the patch and testing it, they can do so.