选择日期时,带有Eonasdan datepicker的敲除bindingHandler不会触发dp.change事件

问题描述

我在选择日期时使用的是Knockout(版本3.4.2),moment(版本2.29.1)和Eonasdan datepicker(版本4.17.47)。

我的问题是用户选择日期时不会触发dp.change事件。在打开日期选择器/小部件(即用户单击日历图标)时触发。

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

我一直在使用eonasdans安装页面上的剔除绑定句柄示例: 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,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>

解决方法

似乎可以正常工作。我向console.log处理程序添加了dp.change语句,还添加了文本绑定以显示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,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类,它查找标记的日期选择器并将其激活,使其绑定两次。

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

删除此选项后,一切正常。