web-dev-qa-db-ja.com

Bootstrap knockpout.js databindを備えた日付ピッカー

この質問は knockoutjs databind with jquery-ui datepicker に似ていますが、jQueryUI datepickerの代わりに Bootstrap datepickers の1つを使用したいと思います。

Bootstrap datepickerのAPIはjquery-uiとは異なり、knockout.jsで動作させるために頭を抱えるのに問題があります。私は それを試すjsFiddle を作成しました。

Bootstrapの日付ピッカーは、独立して日付を格納しないため、はるかに簡単に使用できるようです。ただし、jsFiddleがBootstrap datepickerウィジェットをknockout.jsで使用する適切な方法であるかどうかを知りたいです。

ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor) {
      //initialize datepicker with some optional options
      var options = allBindingsAccessor().datepickerOptions || {};
      $(element).datepicker(options);

      ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).datepicker("destroy");
        });
    },
    update: function(element, valueAccessor) {
    }
};
22
Brian M. Hunt

これは、使用している日付ピッカーを使用してこれを実現する方法のサンプルです。

ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor) {
      //initialize datepicker with some optional options
      var options = allBindingsAccessor().datepickerOptions || {};
      $(element).datepicker(options);

      //when a user changes the date, update the view model
      ko.utils.registerEventHandler(element, "changeDate", function(event) {
             var value = valueAccessor();
             if (ko.isObservable(value)) {
                 value(event.date);
             }                
      });
    },
    update: function(element, valueAccessor)   {
        var widget = $(element).data("datepicker");
         //when the view model is updated, update the widget
        if (widget) {
            widget.date = ko.utils.unwrapObservable(valueAccessor());
            if (widget.date) {
                widget.setValue();            
            }
        }
    }
};

破壊機能があったようには見えなかったので、その部分を削除しました。これは、ウィジェットのchangeDateイベントを処理して、ユーザーが日付を変更したときにビューモデルを更新します。 update関数は、ウィジェットを更新するためにビューモデルが変更されたときに処理します。

値を監視不能にバインドする場合は、もう少しコードが必要になります。それがあなたがサポートする必要があるものであるかどうか私に知らせてください。

http://jsfiddle.net/rniemeyer/KLpq7/

41
RP Niemeyer

私の現在のバージョンは、すでに示された解決策の組み合わせです:

ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {

    var unwrap = ko.utils.unwrapObservable;
    var dataSource = valueAccessor();
    var binding = allBindingsAccessor();

    //initialize datepicker with some optional options
    var options = allBindingsAccessor().datepickerOptions || {};
    $(element).datepicker(options);
    $(element).datepicker('update', dataSource());
    //when a user changes the date, update the view model
    ko.utils.registerEventHandler(element, "changeDate", function (event) {
        var value = valueAccessor();
        if (ko.isObservable(value)) {
            value(event.date);
        }
    });
},
update: function (element, valueAccessor) {
    var widget = $(element).data("datepicker");

    var value = ko.utils.unwrapObservable(valueAccessor());

    //when the view model is updated, update the widget
    if (widget) {
        widget.date = value;
        if (widget.date) {
            widget.setValue();
            $(element).datepicker('update', value)
        }
    }
}};
6
Philipp P

受け入れられた回答は、現在のバージョンの日付ピッカーでは機能しませんでした。入力はオブザーバブルの値で初期化されていませんでした。私はこれを追加した更新されたバインディングを作成しました:

$(element).datepicker('update', dataSource());

これでうまくいくようです。

利用可能な最新の日付ピッカー、Bootstrap、jQuery、およびKnockoutを使用する更新されたフィドルは次のとおりです。 http://jsfiddle.net/krainey/nxhqerxg/

更新:

ユーザーがテキストフィールドの値を手動で編集するときに、日付の選択がオブザーバブルでうまく機能しないという問題が発生しました。ツールはすぐに日付を解析し、結果を入力フィールドに挿入します。

たとえば、ユーザーが10/07/2014を編集しようとして、バックスペースまたは削除を使用して数値(10/0/2014)を削除した場合、結果の値はすぐに解析され、テキスト入力に挿入されます。値がしばらくの間10/0/2014の場合、ピッカーはカレンダーを09/30/2014にシフトし、その値をテキストフィールドに挿入します。月を編集しようとして、値が2014年1月7日だった場合、ピッカーは2014年1月7日にシフトし、その値をテキストフィールドに挿入します。

次のフィドルでその動作を確認できます。

http://jsfiddle.net/krainey/nxhqerxg/10/

フォーカスを検出するためにバインディングを特別なハンドラーで更新し、1回のぼかしイベントをバインドして手動編集を正しく処理する必要がありました。

$(element).on("changeDate", function (ev) {
    var observable = valueAccessor();
    if ($(element).is(':focus')) {
        // Don't update while the user is in the field...
        // Instead, handle focus loss
        $(element).one('blur', function(ev){
            var dateVal = $(element).datepicker("getDate");
            observable(dateVal);
        });
    }
    else {
        observable(ev.date);
    }
});

元の回答で参照されているフィドルは、これを反映するように更新されています。

http://jsfiddle.net/krainey/nxhqerxg/

5
kiprainey

これが私が終わったものです

ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
    //initialize datepicker with some optional options

    var options = {
        autoclose: true,
        format: 'yyyy-mm-dd',
    }

    //var options = allBindingsAccessor().datepickerOptions || {};
    $(element).datepicker(options);

    //when a user changes the date, update the view model
    ko.utils.registerEventHandler(element, "changeDate", function (event) {
        var value = valueAccessor();

        if (ko.isObservable(value)) {
            var myDate = event.date;
            var month = myDate.getMonth() + 1;
            var monthText = month;

            if (month < 10)
                monthText = "0" + month;

            var day1 = parseInt(myDate.getDate());
            var dayText = day1;

            if (day1 < 10)
                dayText = '0' + day1;

            value(myDate.getFullYear() + '-' + monthText + '-' + dayText);
        }
    });
},
update: function (element, valueAccessor) {

    var widget = $(element).data("datepicker");
    //when the view model is updated, update the widget
    if (widget) {
        widget.date = ko.utils.unwrapObservable(valueAccessor());
        widget.setValue(widget.date);
    }
}};
2
Muhammad Amin