使用 Eonasdan 日期选择器的 Knockout bindingHandler 在选择日期时不会触发 dp.change 事件

Knockout bindingHandler with Eonasdan datepicker does not fire dp.change event when selecting date

我正在使用 Knockout(3.4.2 版)、moment(2.29.1 版)和 Eonasdan datepicker(4.17.47 版)插件来选择日期。

我的问题是当用户选择日期时 dp.change 事件没有被触发。它在 datepicker/widget 打开时触发,即用户单击日历图标。

结果是用户选择的第一个日期被忽略(事件在实际选择日期之前触发)并且只有当用户再次打开日期选择器并且事件触发时才会更新日期。

我一直在使用 eonasdans 安装页面中的 knockout bindinghandle 示例: http://eonasdan.github.io/bootstrap-datetimepicker/Installing/

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

        //when a user changes the date, update the view model
        ko.utils.registerEventHandler(element, "dp.change", function (event) {
            var value = valueAccessor();
            if (ko.isObservable(value)) {
                if (event.date != null && !(event.date instanceof Date)) {
                    value(event.date.toDate());
                } else {
                    value(event.date);
                }
            }
        });

        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            var picker = $(element).data("DateTimePicker");
            if (picker) {
                picker.destroy();
            }
        });
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        var picker = $(element).data("DateTimePicker");
        //when the view model is updated, update the widget
        if (picker) {
            var koDate = ko.utils.unwrapObservable(valueAccessor());

            //in case return from server datetime i am get in this form for example /Date(93989393)/ then fomat this
            //koDate = (typeof (koDate) !== 'object') ? new Date(parseFloat(koDate.replace(/[^0-9]/g, ''))) : koDate;

            picker.date(koDate);
        }
    }
};

我的淘汰赛视图是这样的:

var exportLicenserModel = function () {
        var self = this;
        self.Startdatum = ko.observable((new moment()).month(0).date(1));
}

而 HTML 是:

<div class='input-group js-date'>
  <input type="text" class="form-control" id="licenseStartDate" data-bind="datepicker: Startdatum, datepickerOptions: { locale: 'sv', format: 'YYYY-MM-DD', useCurrent: false }" />
  <span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
</div>

似乎工作正常。我向 dp.change 处理程序添加了一个 console.log 语句,还添加了一个 text-binding 来显示 Startdatum 的当前值。调用处理程序并更新值。看看下面的片段:

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

    //when a user changes the date, update the view model
    ko.utils.registerEventHandler(element, "dp.change", function(event) {
      var value = valueAccessor();
      if (ko.isObservable(value)) {
        if (event.date != null && !(event.date instanceof Date)) {
          value(event.date.toDate());
        } else {
          value(event.date);
        }
      }
      console.log(`Changed to ${value()}`);
    });

    ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
      var picker = $(element).data("DateTimePicker");
      if (picker) {
        picker.destroy();
      }
    });
  },
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {

    var picker = $(element).data("DateTimePicker");
    //when the view model is updated, update the widget
    if (picker) {
      var koDate = ko.utils.unwrapObservable(valueAccessor());

      //in case return from server datetime i am get in this form for example /Date(93989393)/ then fomat this
      //koDate = (typeof (koDate) !== 'object') ? new Date(parseFloat(koDate.replace(/[^0-9]/g, ''))) : koDate;

      picker.date(koDate);
    }
  }
};

var exportLicenserModel = function() {
  var self = this;
  self.Startdatum = ko.observable((new moment()).month(0).date(1));
}

ko.applyBindings(new exportLicenserModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>

<div class='input-group js-date' style="position: relative">
  <input type="text" class="form-control" id="licenseStartDate" data-bind="datepicker: Startdatum, datepickerOptions: { locale: 'sv', format: 'YYYY-MM-DD', useCurrent: false }" />
  <span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
</div>
<p>StartDatum: <strong data-bind="text: Startdatum"></strong></p>

我找到了 dp.change 事件似乎没有触发的原因。

项目中有一个过时的 jQuery class 查找标记的日期选择器并激活它们,使它们绑定两次。

$('.js-date').datetimepicker({ locale: 'sv', format: 'YYYY-MM-DD', useCurrent: false });

删除它后,一切正常。