Datepicker で任意の年月を初期表示する

最終更新日時:2017-03-23 00:00:00
jQuery UI:Datepicker

jQuery UI の Datepicker は大変便利だしカスタマイズもいろいろ出来るのですが、ホントにちょっとしたことが出来なかったりします。
例えば、以下の条件を全て満たすようなことが出来ません。

・日付入力域は持たさず、常時表示とする
・初期表示の年月は任意に指定可能とする
・ただし、日付の指定はしない(指定すると指定した日付のスタイルが変わってしまうので)
・初期表示後、年月の移動は可能とする

要するに、常時表示の初期値として年月を指定した上であとは普通の動き、、、といったことが出来ません。
こんなのオプションにあっても良さそうな話ですよね(^_^;
意外と厄介な問題でした。

この問題に関するメモです。


動的表示で年月移動無しのケース


ネット上で調べて有用だったのは、まず以下の記事でした。

jQuery の datepicker でカレンダーの表示月を変える

上記は正確には検証はしていないのですが、動的表示 (input が対象)である以外は同じ条件に見えます。
以下で初期表示年月を変更可能であるという内容です。

 $("input#test").datepicker({
    beforeShow : function(input, inst){
        setTimeout(_ => {
            inst.drawYear = 2020
            inst.drawMonth = 0
            $.datepicker._updateDatepicker(inst)
        }, 0)
    }
 })


この記事を参考にして冒頭の条件の内容を実装してみたのですが、以下の問題が出てきました。

・常時表示だと beforeShow 指定がなぜか有効にならない!

原因は不明ですが、今のところバグとしか思えないですね。。。
といったわけで、上記記事の内容が使えるかどうか検証するためには、まずは beforeShow を常時表示で有効にしなくてはならないことになりました。

なお、上記記事中に Datepicker のコードへのリンクがあり、これが非常に参考になります。

https://github.com/jquery/jquery-ui/blob/master/ui/widgets/datepicker.js


常時表示で beforeShow を有効にする


この情報ですが、調べても調べても日本語の情報は全く出てきません。
仕方なく英語まで手を広げてみたところ以下の記事が見つかりました。

beforeShow event not firing on jQueryUI Datepicker

結論としては、CDN ではなく JS ファイルをダウンロードして直接修正するか、メソッドをオーバーライドするのが良いということのようです。
もちろん直接修正した方が分かりやすくて簡単なのですが、独自修正をオリジナルに入れてしまうと管理が面倒臭いことになるので、今回はオーバーライドする方法を選びました。
ほぼ、上記記事の抜粋です。

以下のような JS ファイルを作成します。

 (function ($) {
    $.extend($.datepicker, {
 
        // Reference the orignal function so we can override it and call it later
        _inlineDatepicker2: $.datepicker._inlineDatepicker,
 
        // Override the _inlineDatepicker method
        _inlineDatepicker: function (target, inst) {
 
            // Call the original
            this._inlineDatepicker2(target, inst);
 
            var beforeShow = $.datepicker._get(inst, 'beforeShow');
 
            if (beforeShow) {
                beforeShow.apply(target, [target, inst]);
            }
        }
    });
 }(jQuery));


上記のオーバーライド用の JS を読み込ませると、常時表示 (inline) 時にも beforeShow が有効になります。


年月移動対応


これで最初の記事の以下のコードがようやく検証できます。
常時表示なので、#datepicker は div 要素であることだけが、上の記事との相違点です。

 $("#datepicker").datepicker({
    beforeShow : function(input, inst){
        setTimeout(_ => {
            inst.drawYear = 2020
            inst.drawMonth = 0
            $.datepicker._updateDatepicker(inst)
        }, 0)
    }
 })


しかし、、、、うまくいきません。
表示は正常なのですが、年月移動するとおかしな挙動になります。
どうやら、表示時の年月データとカレントの年月データを別に持っているのが原因のように思います。

結論を書いてしまうと、以下の指定で期待した動作となりました。

    beforeShow : function(input, inst) {
        inst.drawYear  = inst.selectedYear  = 2020;
        inst.drawMonth = inst.selectedMonth = 0;
        $.datepicker._updateDatepicker(inst);
    },


要するに、drawYear, drawMonth だけでなく、selectedYear, selectedMonth も同様に設定するということです。
setTimeout による非同期処理は不要でした。

結論:
https://github.com/jquery/jquery-ui/blob/master/ui/widgets/datepicker.js を見つつ、オーバーライドしていけばたいていのことは出来そうです(笑)

お問い合わせは 掲示板 にて。