Help us understand the problem. What is going on with this article?

Yii 1.1.x で jQuery UI Datepicker を使う

More than 3 years have passed since last update.

日付の入力に便利な jQuery UI Datepicker が Yii 1.1.x でも CJuiDatePicker としてサポートされています。その使い方を具体的な例を示して解説します。

基本

フォームに日付を入力するテキスト・フィールドがあるとします。

_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>

CActiveForm を使っているという想定です。このテキスト・フィールドを CJuiDatePicker に置き換えます。

_form.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>

こうやると、CJuiDatePikcer ウィジェットが、必要な javascript ファイルをロードし、テキスト・フィールドを HTML で書き、それを Datepicker に変換するスクリプトを登録してくれます。つまり、

  1. Datepicker に必要な javascript ファイル (jQuery, jQuery UI) や CSS ファイルを自分でロードする必要は無い。
  2. Datepicker 用のテキスト・フィールドを自分で書く必要は無い。
  3. テキスト・フィールドを Datepicker に変換する javascript コードを自分で書く必要は無い。

ということです。CJuiDatePicker ウィジェットが全部やってくれます(うーん、そう簡単に行かない場合があるのですが、まあ、それは後回しにしましょう)。

上記の例では、CJuiDatePicker を CActiveForm::textField と同じ感覚で使っています。つまり、 'model' 属性に $model をセットし、 'attribute' 属性に $model の 'from_date' 属性をセットしています。このようにやると、CActiveForm::textField と同じロジックで入力フィールドの名前を付けて、その値をモデルの属性と結び付けてくれます。

CActiveForm を使わない場合は、 'name''value' の属性を指定して、自分で入力フィールドの名前を付け、値を設定することが出来ます。CHtml::textField に対応する使い方ですね。

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

注意すべきは、'model' と 'attribute' のペアと 'name' と 'value' のペアは排他的である、ということです。混ぜないこと。

日本語化

日本語にします。

_form.php
<?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',
    ),
)); 
?>

最初に書いた時は、 'language' だけじゃ駄目みたいなので、 'i18nScriptFile' も指定していました。
今では、 'language' の指定だけで、日本語になります。

テーマを適用

自作の jQuery UI テーマを適用します。

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

'/css/jui' の下に 'softark' というテーマが置いてあるという想定です。jQuery UI のテーマは ThemeRoller で作ります。その説明は省略。気に入ったものを作るのは、なかなか難しい。

オプションを指定

いろいろとオプションを指定します。

_form.php
<?php
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
    'model' => $model,
    'attribute' => 'date_from',
    'language' => 'ja',
    'themeUrl' => Yii::app()->baseUrl . '/css/jui',
    'theme' => 'softark',
    'cssFile' => 'jquery-ui-1.9.2.custom.css',
    'options' => array(
        'showOn' => 'both',             // ボタンでも開く
        'dateFormat' => 'yy-mm-dd',     // "2012-12-25" の形式
        'showOtherMonths' => true,      // 他の月の日付も表示
        'selectOtherMonths' => true,    // 他の月の日付も選択可能
        'changeYear' => true,           // 年を変更可能
        'changeMonth' => true,          // 月を変更可能
        'yearRange' => '2000:2099',     // 年の範囲
        'minDate' => '2000-01-01',      // 日付の最小値
        'maxDate' => '2099-12-31',      // 日付の最大値
        'showButtonPanel' => true,      // ボタン・パネルを表示
    ),
    'htmlOptions' => array(
        'size' => '10',
        'maxlength' => '10',
    ),
)); 
?>

ここらは、各自の好みです。オプションについての詳細は、DatePicker の デモページ や、API を参照して下さい。

開くときと閉じるときのアニメーションの指定 'showAnim' は、ぼくの経験では、使わない方が動作が安定します。特に、画面上で二つ以上の Datepicker を使いたい場合は、やめておきましょう。

表示の調整

が、しかし、表示が気にくわない。何よりも、年と月のドロップ・ダウンが大きすぎて、ヘッダが二段になってしまうのが致命的です。不細工なこと、この上ない。それに、もう少しフォントを小さくしたいですね。

で、ThemeRoller が作った CSS ファイルを手作業で修正します。

jquery-ui-1.9.2.custom.css
/* Component containers
----------------------------------*/
/* --- 削除 : メインのフォント指定に従わせる ---
.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; }
*/
...
/* 追加 : フォントを小さめにする */
#ui-datepicker-div { font-size: 80%;}
button.ui-datepicker-trigger { font-size: 80%; line-height: 1.4em; }
...

/* --- 年と月のレイアウト ... 気にくわないので大幅変更 ---
.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%; }
/* 馬鹿ブラウザにも気を使ってやる */
* html .ui-datepicker .ui-datepicker-title select.ui-datepicker-month { width: 30%; }
* html .ui-datepicker .ui-datepicker-title select.ui-datepicker-year { width: 35%;}
/* ハイライトに関する微修正 */
.ui-datepicker .ui-state-active, .ui-datepicker .ui-state-active.ui-state-highlight { border-color: #0b5110;}
.ui-datepicker .ui-state-highlight { border-color: #448844;}

こんな具合に、いろいろ、ごちょごちょと弄る訳でありますよ。このあたり、こうすれば良いという、はっきりした正解は無いと思います。

GCalHolidays.js で土日祝日に対応

便利な GCalHolidays.js を利用させてもらいます。

_form.php
<?php
Yii::app()->cientScript->registerScriptFile(
    Yii::app()->baseUrl . '/js/GCalHolidays.js',
    CClientScript::POS_END
);
?>

これで、日曜日、土曜日、祝日(そう、日本の祝日ですよ!)が、カレンダー上で色分けして表示されるようになります。

デフォルトの色付けはケバイので(ごめん)、ちょっとだけ修正させてもらいます。

GCalHolidays.js
/** jQuery UI Datepicker用のstyle(Themeに合わせてお好みで上書きして使う) */
datepickerStyles: {
    // sunday:   "background-image: none; background-color: #f99", //日曜日
    // saturday: "background-image: none; background-color: #6cf", //土曜日
    // holiday:  "background-image: none; background-color: #f9f"  //祝日
    sunday:   "color: #f00", //日曜日
    saturday: "color: #0af", //土曜日
    holiday:  "color: #f00"  //祝日
}

なお、GCalHolidays.js は、バージョン 0.6.0 において、Google Calendar API v3 への対応に伴い、サーバ側のプログラムが必要なものに変りました。今まで通り、クライアント側の javascript だけで済ませたい、と言う場合は、GCalendar Holidays - jui Datepicker 専用版 をご覧下さい。

AJAX で更新される領域内で使う場合

特定の領域を AJAX でごっそり入れ替えるという処理は、最近のウェブ・アプリでは、きわめて頻繁に発生します。その領域の中で Datepicker を使いたい場合(フォームの内容を AJAX で更新したい場合など)は、ちょっとだけ注意が必要です。

jQuery UI Datepicker は、既存の HTML コードに変更を加えることによって、テキスト・フィールドを Datepicker に変身させています。ところが、その HTML コードが AJAX によって更新されると、Datepicker であったテキスト・フィールドは、素のテキスト・フィールドに戻ってしまいます。

ページをロードした直後は Datepicker が動くのに何かをやった後に Datepicker が動かなくなる、というのは、たいてい、そういう理由です。

これに対しては、素のテキスト・フィールドをもう一度 Datepicker に作り直す、という処理をする以外に解決方法はありません。

二つの解法があります:

  1. サーバが返す AJAX のレスポンスに Datepicker 用のスクリプトをもう一度含める。
  2. AJAX による更新処理をした後に Datepicker 変換作業を(手作業で)する。

第一の方法は、やったことがないので、よく分りません。CController::renderPartial() の 4 番目のパラメータを true にするやつですね。ところが、これが、CClientScript::scriptMap を弄って jQuery を再送しないように細工する必要がある、とか何とか、いろいろと面妖な感じがして、どうも、やってみる気になれないのです。

僕が好むのは、第二の方法です。サーバからのレスポンスにはスクリプトを含めません。
例えばこんなコードを使います。

$('#submit-button').click(function() {
    // フォームの内容を AJAX で POST
    $.ajax({
        'type' : 'POST',
        'url' : 'hoge-update',
        'dataType' : 'json',
        'data' : $('#hoge-form').serialize(),
        'success' : function(data){
            // フォームの内容を更新
            $('#hoge-form').html(data.contents);
            // Datepicker 再設定
            $('#hoge-form .d-picker').datepicker();
        }
    });
});

ちょっといい加減ですが、要は、AJAX で内容を更新した後に、jQuery UI の datepicker() 関数を呼んで、テキスト・フィールドを再度 Datepicker に作り直す訳です。

あ、つまり、もう Yii の事は忘れて、jQuery でゴリゴリという世界です。jQuery は全然わからんとか、jQuery UI のドキュメントを読むのが苦痛だとかでない限り、この方が何かと見通しが良くて、楽ちんだと思いますよ。

とは言うものの、初期ロードのためには、CJuiDatePicker を使ってます。その方が楽だから。

で、AJAX のことを考えた場合は、下記のような書き方をする方が便利です。

_form.php
<?php
$this->widget('zii.widgets.jui.CJuiDatePicker', array(
    ...
    'defaultOptions' => array(
        'showOn' => 'both',
        ...
    ),
    'htmlOptions' => array(
        ...
        'class' => 'd-picker',
    ),
)); 
?>

'htmlOptions' で 'class' を指定します。これは 'id' でも構いません。要は、後で jQuery でセレクタとして使おうという魂胆です。

もうひとつ、 'options' の代りに 'defaultOptions' を使っています。こうしておくと、jQuery UI の datepicker 関数を呼ぶときに、オプションを省略できます。

softark
山の中の半農半プログラマ。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした