Difference between #8 and #9 of jQuery UI Datepicker

unchanged
Title
jQuery UI Datepicker
unchanged
Category
How-tos
unchanged
Tags
CJuiDatePicker, Datepicker
changed
Content
We all love the convenient gadget, namely **jQuery UI Datepicker** as an input
element for date. Yii supports it as **CJuiDatePicker**. Let's see how to use
it.

Basics
------

Imagine we have a text field for date in our form.

~~~
[php]
<div class="row">
<?php echo $form->labelEx($model,'date_from'); ?>
<?php
echo $form->textField($model, 'date_from', array(
	'size' => 10,
	'maxlength' => 10,
));
?>
<?php echo $form->error($model,'date_from'); ?>
</div>
~~~

As you see, we are using a CActiveForm here. And now replace the text field with
a CJuiDatePicker.

~~~
[php]
<div class="row">
<?php echo $form->labelEx($model,'date_from'); ?>
<?php
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
	'model' => $model,
	'attribute' => 'date_from',
	'htmlOptions' => array(
		'size' => '10',			// textField size
		'maxlength' => '10',	// textField maxlength
	),
));
?>
<?php echo $form->error($model,'date_from'); ?>
</div>
~~~

Basically this is all that you have to do.

1. You don't need to load the javescript files (i.e. jQuery and jQuery UI) and
CSS files by yourself.
2. You don't need to write a text field by yourself.
3. You don't need to write a script to convert the text field into Datepicker by
yourself.

CJuiDatePicker will do all the tasks for you. (Well, things could be a little
complicated in some situations. We will discuss it later.)

In the example above, we are using CJuiDatePicker like a CActiveForm::textField,
setting `$model` to **model** and 'date_from' attribute of `$model` to
**attribute**. By this settings, CJuiDatePicker will use the same logic as
CActiveForm::textField to name the input field and connect the value to the
attribute of the model.

If you don't use CActiveForm, you may use **name** and **value** to specify the
name of the input field and the value of it. It correspond to the usage of
CHtml::textField.

~~~
[php]
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
	'name' => 'date_from',
	'value' => $fromDateValue,
	'htmlOptions' => array(
		'size' => '10',			// textField size
		'maxlength' => '10',	// textField maxlength
	),
));
~~~

> Note: You have to use either **model-attribute** pair or **name-value**
pair. They are mutually exclusive. Do not mix them up.

![Basic Datepicker](http://www.softark.net/images/datepicker-01.png "Basic
Datepicker")

Localization
------------

Now, let's localize the Datepicker.

~~~
[php]
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
	'model' => $model,
	'attribute' => 'date_from',
	'language' => 'ja',
	// 'i18nScriptFile' => 'jquery.ui.datepicker-ja.js',
	'htmlOptions' => array(
		'size' => '10',
		'maxlength' => '10',
	),
)); 
~~~

We have to specify **'language'**.
Generally you don't to need to specify **'i18nScriptFile'** if you are using the
latest version of jQuery UI.

![Localized Datepicker](http://www.softark.net/images/datepicker-02.png
"Localized Datepicker")

Theming
-------

And we are applying a jQuery UI theme.

~~~
[php]
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
	'model' => $model,
	'attribute' => 'date_from',
	'language' => 'ja',
	'i18nScriptFile' => 'jquery.ui.datepicker-ja.js',
	'themeUrl' => Yii::app()->baseUrl . '/css/jui',
	'theme' => 'softark',
	'cssFile' => 'jquery-ui-1.9.2.custom.css',
	'htmlOptions' => array(
		'size' => '10',
		'maxlength' => '10',
	),
)); 
~~~

We are in the assumption that '/css/jui' holds a theme named 'softark'. You have
to create a jQuery UI theme using
[ThemeRoller](http://jqueryui.com/themeroller/). It's not quite easy to create a
good looking theme, though.

![Themed Datepicker](http://www.softark.net/images/datepicker-03.png
"Themed Datepicker")


Options
-------

We can set various options.

~~~
[php]
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
	'model' => $model,
	'attribute' => 'date_from',
	'language' => 'ja',
	'i18nScriptFile' => 'jquery.ui.datepicker-ja.js',
	'themeUrl' => Yii::app()->baseUrl . '/css/jui',
	'theme' => 'softark',
	'cssFile' => 'jquery-ui-1.9.2.custom.css',
	'options' => array(
		'showOn' => 'both',				// also opens with a button
		'dateFormat' => 'yy-mm-dd',		// format of "2012-12-25"
		'showOtherMonths' => true,		// show dates in other months
		'selectOtherMonths' => true,	// can seelect dates in other months
		'changeYear' => true,			// can change year
		'changeMonth' => true,			// can change month
		'yearRange' => '2000:2099',		// range of year
		'minDate' => '2000-01-01',		// minimum date
		'maxDate' => '2099-12-31',		// maximum date
		'showButtonPanel' => true,		// show button panel
	),
	'htmlOptions' => array(
		'size' => '10',
		'maxlength' => '10',
	),
)); 
~~~

The options are all up to your choice. Please see [DatePicker
DEMO](http://jqueryui.com/datepicker/) and
[API](http://api.jqueryui.com/datepicker/) for detailed information.

> Note: My experience tells that the Datepicker works more stable without
**'showAnim'** option. Especially when you want to use 2 or more instances on
the same screen, you would be better not set this option.

![Datepicker with Options](http://www.softark.net/images/datepicker-04.png
"Datepicker with Options")

Adjusting the appearance
------------------------

But, we don't like the appearance of it at all. The header is divided into 2
rows because the dropdowns of year and month are a little too large. And we
would like the font to be a little smaller.

Hmm, we have to tweak the CSS that ThemeRoller has created.

~~~
[css]
/* Component containers
----------------------------------*/
/* --- delete : use the default font of my site css ---
.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif;
font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button {
font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
*/
...
/* --- add : font should be a little smaller --- */
#ui-datepicker-div { font-size: 80%;}
button.ui-datepicker-trigger { font-size: 80%; line-height: 1.4em; }
...

/* --- layout of year and month ... have to modify a bit ---
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
*/
.ui-datepicker select.ui-datepicker-month { with: 35%; }
.ui-datepicker select.ui-datepicker-year { width: 40%; }
/* --- for fxxking stupid browsers --- */
* html .ui-datepicker .ui-datepicker-title select.ui-datepicker-month { width:
30%; }
* html .ui-datepicker .ui-datepicker-title select.ui-datepicker-year { width:
35%;}
/* --- highliting --- */
.ui-datepicker .ui-state-active, .ui-datepicker
.ui-state-active.ui-state-highlight { border-color: #0b5110;}
.ui-datepicker .ui-state-highlight { border-color: #448844;}
~~~

So, the boring part of the task has been done. Of course you have to do your own
job here. There's no standard way of doing it.

![Datepicker](http://www.softark.net/images/datepicker-05.png
"Datepicker")

Holidays
--------

I'm going to use
[GCalHolidays.js](http://0-oo.net/sbox/javascript/google-calendar-holidays). It
will enable you to color Sundays, Saturdays and Japanese Holidays with different
colors.

Yes, I'm sorry, this part is Japanese specific. But you may find your locale
specific counterpart somewhere on the web.

~~~
[php]
Yii::app()->cientScript->registerScriptFile(
	Yii::app()->baseUrl . '/js/GCalHolidays.js',
	CClientScript::POS_END
);
~~~

![Datepicker with Holidays](http://www.softark.net/images/datepicker.png
"Datepicker with Holidays")

Inside an AJAX updated area
---------------------------

In today's web applications, it's a common practice to update/replace the
content of a specific area using **AJAX**. And if you want to use Datepicker
inside such an area (e.g. in a form that will be ajax updated), you will need
some extra work.

jQuery UI Datepicker modifies the existing HTML code to transform the ordinary
text field into a Datepicker. So when the HTML code has been updated by an AJAX,
the Datepicker will return to an plain text field.

You may encounter an issue like this: the Datepicker works just fine when the
page has been loaded for the first time, but after you have done something in
the page the Datepicker won't work anymore. Most probably the cause of the issue
is that the HTML code has been updated by AJAX and the Datepicker has been reset
to the plain text field.

To solve this kind of issue, we have to convert the plain text field to a
Datepicker again after every ajax updating.

There are 2 ways to do that:

1. Include a script to re-create the Datepicker in the AJAX response.
2. Manually re-create the Datepicker after AJAX updating.

I don't have much to say about the 1st approach, because I've never used it.
Probably you have to set the 4th parameter of Controller::renderPartial() to
`true` to include the script in AJAX response. But, at the same time, you have
to tweak CClientScript::scriptMap to avoid the duplication of jQuery and jQuery
UI. ... I'm not sure. Personally I feel this approach is tricky, hacky and
unstable. I don't like it.

I prefer the 2nd approach. I will not include any javascript in the response
from the server. It goes like this:

~~~
[javascript]
$('#submit-button').click(function() {
	// post the form content by ajax
	$.ajax({
		'type' : 'POST',
		'url' : 'foo-update',
		'dataType' : 'json',
		'data' : $('#foo-form').serialize(),
		'success' : function(data){
			// update the form
			$('#foo-form').html(data.contents);
			// re-create Datepicker
			$('#foo-form .d-picker').datepicker();
		}
	});
});
~~~

It's just a rough skech, but the point is that we call datepicker() function of
jQuery UI after the AJAX updating to re-create the Datepicker.

Yes, I'm doing a pure jQuery programming here. Although usually the jQuery
support of Yii is quite convenient and useful, the things will be much easier
with plain jQuery programming when the things got a little complicated.

But I will continue to use CJuiDatePicker for the initial loading of the
Datepicker, because it's much more easy. And the following is a sample code to
create a Datepicker when it has to be updated by AJAX.

~~~
[php]
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
	...
	'defaultOptions' => array(
		'showOn' => 'both',
		...
		... more options here ...
		...
	),
	'htmlOptions' => array(
		...
		'class' => 'd-picker',
	),
)); 
~~~

We set **'class'** in 'htmlOptions' because we want to select this element using
jQuery. Of course you may use **'id'** instead.

And we use **'defaultOptions'** instead of **'options'**. By doing this, we will
be able to call datepicker() function of jQuery UI without explicitly specifying
the options.

Links
------------------
- [Using CJuiDatePicker for CGridView
filter](http://www.yiiframework.com/wiki/318/using-cjuidatepicker-for-cgridview-filter/)
- Japanese Translation: [Yii で jQuery UI Datepicker
を使う](http://qiita.com/items/b03770d8f7d1ff60f3d7)
Write new article