jQuery UI datepicker更改事件没有被KnockoutJS捕获

我试图用jQuery UI使用KnockoutJS。 我有一个附带dateselect器的input元素。 我目前正在运行knockout.debug.1.2.1.js ,似乎改变事件从来没有被捕获。 元素看起来像这样:

 <input type="text" class="date" data-bind="value: RedemptionExpiration"/> 

我什至试图改变valueUpdate事件types,但无济于事。 Chrome好像在它改变值之前引起一个focus事件,但是IE没有。

是否有一些“重新绑定所有绑定”的Knockout方法? 我在技术上只需要将值发送回服务器之前更改的值。 所以我可以忍受这种解决方法。

我认为问题是dateselect器的错,但我不知道如何解决这个问题。

有任何想法吗?

我认为对于jQuery UIdateselect器,最好使用一个自定义绑定,它将使用datepicker提供的API使用Date对象进行读取/写入。

绑定可能看起来像(从我的答案这里 ):

 ko.bindingHandlers.datepicker = { init: function(element, valueAccessor, allBindingsAccessor) { //initialize datepicker with some optional options var options = allBindingsAccessor().datepickerOptions || {}, $el = $(element); $el.datepicker(options); //handle the field changing by registering datepicker's changeDate event ko.utils.registerEventHandler(element, "changeDate", function () { var observable = valueAccessor(); observable($el.datepicker("getDate")); }); //handle disposal (if KO removes by the template binding) ko.utils.domNodeDisposal.addDisposeCallback(element, function() { $el.datepicker("destroy"); }); }, update: function(element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), $el = $(element); //handle date data coming via json from Microsoft if (String(value).indexOf('/Date(') == 0) { value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1"))); } var current = $el.datepicker("getDate"); if (value - current !== 0) { $el.datepicker("setDate", value); } } }; 

你会像这样使用它:

 <input data-bind="datepicker: myDate, datepickerOptions: { minDate: new Date() }" /> 

在jsFiddle中示例: http : //jsfiddle.net/rniemeyer/NAgNV/

这里是一个RP尼迈耶的答案,将与在这里find的基因敲除validation脚本的工作版本: http : //github.com/ericmbarnard/Knockout-Validation

 ko.bindingHandlers.datepicker = { init: function (element, valueAccessor, allBindingsAccessor) { //initialize datepicker with some optional options var options = allBindingsAccessor().datepickerOptions || {}; $(element).datepicker(options); //handle the field changing ko.utils.registerEventHandler(element, "change", function () { var observable = valueAccessor(); observable($(element).val()); if (observable.isValid()) { observable($(element).datepicker("getDate")); $(element).blur(); } }); //handle disposal (if KO removes by the template binding) ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $(element).datepicker("destroy"); }); ko.bindingHandlers.validationCore.init(element, valueAccessor, allBindingsAccessor); }, update: function (element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); //handle date data coming via json from Microsoft if (String(value).indexOf('/Date(') == 0) { value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1"))); } current = $(element).datepicker("getDate"); if (value - current !== 0) { $(element).datepicker("setDate", value); } } }; 

更改事件处理程序将所input的值传递给validation脚本,而不是将date传递给validation脚本,然后仅在有效时将观察值设置为date。 我还添加了这里讨论的自定义绑定所需的validationCore.init:

http://github.com/ericmbarnard/Knockout-Validation/issues/69

我还添加了rpenrose的build议,对变化模糊,以消除一些讨厌的dateselect器scheme阻碍事情。

我使用了不同的方法。 由于knockout.js似乎并没有改变事件,所以我强迫datepicker在closures之后调用change()来input它的input。

 $(".date").datepicker({ onClose: function() { $(this).change(); // Forces re-validation } }); 

尽pipe所有这些答案都为我节省了很多工作,但是他们没有一个完全为我工作。 selectdate后,绑定的值不会更新。 我只能使用键盘更改date值时才能更新它,然后单击input框。 我通过用syb的代码增加RP Niemeyer的代码来解决这个问题,得到:

 ko.bindingHandlers.datepicker = { init: function (element, valueAccessor, allBindingsAccessor) { //initialize datepicker with some optional options var options = allBindingsAccessor().datepickerOptions || {}; var funcOnSelectdate = function () { var observable = valueAccessor(); observable($(element).datepicker("getDate")); } options.onSelect = funcOnSelectdate; $(element).datepicker(options); //handle the field changing ko.utils.registerEventHandler(element, "change", funcOnSelectdate); //handle disposal (if KO removes by the template binding) ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $(element).datepicker("destroy"); }); }, update: function (element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); if (typeof(value) === "string") { // JSON string from server value = value.split("T")[0]; // Removes time } var current = $(element).datepicker("getDate"); if (value - current !== 0) { var parsedDate = $.datepicker.parseDate('yy-mm-dd', value); $(element).datepicker("setDate", parsedDate); } } }; 

我怀疑把可观察($(element).datepicker(“getDate”)); 声明在自己的function和注册与options.onSelect做了诡计?

感谢这篇文章,我发现它非常有用。

如果您希望DatePicker的行为与JQuery UI默认行为完全相同,那么我build议在change事件处理函数中添加模糊元素:

  //handle the field changing ko.utils.registerEventHandler(element, "change", function () { var observable = valueAccessor(); observable($(element).datepicker("getDate")); $(element).blur(); }); 

我通过改变我包含的脚本文件的顺序来解决这个问题:

 <script src="@Url.Content("~/Scripts/jquery-ui-1.10.2.custom.js")"></script> <script src="@Url.Content("~/Scripts/knockout-2.2.1.js")"></script> 

与RP Niemeyer相同,但更好地支持WCF DateTime,时区和使用DatePicker onSelect JQuery属性。

  ko.bindingHandlers.datepicker = { init: function (element, valueAccessor, allBindingsAccessor) { //initialize datepicker with some optional options var options = allBindingsAccessor().datepickerOptions || {}; var funcOnSelectdate = function () { var observable = valueAccessor(); var d = $(element).datepicker("getDate"); var timeInTicks = d.getTime() + (-1 * (d.getTimezoneOffset() * 60 * 1000)); observable("/Date(" + timeInTicks + ")/"); } options.onSelect = funcOnSelectdate; $(element).datepicker(options); //handle the field changing ko.utils.registerEventHandler(element, "change", funcOnSelectdate); //handle disposal (if KO removes by the template binding) ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $(element).datepicker("destroy"); }); }, update: function (element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); //handle date data coming via json from Microsoft if (String(value).indexOf('/Date(') == 0) { value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1"))); } current = $(element).datepicker("getDate"); if (value - current !== 0) { $(element).datepicker("setDate", value); } } }; 

请享用 :)

http://jsfiddle.net/yechezkelbr/nUdYH/

我认为它可以做得更容易: <input data-bind="value: myDate, datepicker: myDate, datepickerOptions: {}" />

所以你不需要在init函数中手动更改处理。

但在这种情况下,您的“myDate”variables将只获得可见值,而不是Date对象。

另外,你可以在绑定中指定这个:

更新:

  function (element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), current = $(element).datepicker("getDate"); if (typeof value === "string") { var dateValue = new Date(value); if (dateValue - current !== 0) $(element).datepicker("setDate", dateValue); } } 

基于瑞安的解决scheme,myDate返回标准的datestring,这不是我的理想情况。 我用date.js来parsing这个值,所以它总是会返回你想要的date格式。 看看这个例子的小提琴例子 。

 update: function(element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), current = $(element).datepicker("getDate"); var d = Date.parse(value); if (value - current !== 0) { $(element).datepicker("setDate", d.toString("MM/dd/yyyy")); } } 

我需要重复更新我的数据从服务器遇到这个,但没有完成我的需求共享下面的工作(我的date格式/date(1224043200000)/):

 //Object Model function Document(data) { if (String(data.RedemptionExpiration).indexOf('/Date(') == 0) { var newDate = new Date(parseInt(data.BDate.replace(/\/Date\((.*?)\)\//gi, "$1"))); data.RedemptionExpiration = (newDate.getMonth()+1) + "/" + newDate.getDate() + "/" + newDate.getFullYear(); } this.RedemptionExpiration = ko.observable(data.RedemptionExpiration); } //View Model function DocumentViewModel(){ ///additional code removed self.afterRenderLogic = function (elements) { $("#documentsContainer .datepicker").each(function () { $(this).datepicker(); }); }; } 

在模型正确输出后,我添加了一个模板文件knockoutjs :

 <div id="documentsContainer"> <div data-bind="template: { name: 'document-template', foreach: documents, afterRender: afterRenderLogic }, visible: documents().length > 0"></div> </div> //Inline template <script type="text/html" id="document-template"> <input data-bind="value: RedemptionExpiration" class="datepicker" /> </script> 

很less有人要求dynamicdateselect器选项。 在我的情况下,我需要一个dynamic的date范围 – 所以第一个input定义第二个的最小值,第二个设置第一个的最大值。 我通过扩展RP尼迈耶的经理来解决这个问题。 所以对他来说:

 ko.bindingHandlers.datepicker = { init: function(element, valueAccessor, allBindingsAccessor) { //initialize datepicker with some optional options var options = allBindingsAccessor().datepickerOptions || {}, $el = $(element); $el.datepicker(options); //handle the field changing by registering datepicker's changeDate event ko.utils.registerEventHandler(element, "change", function() { var observable = valueAccessor(); observable($el.datepicker("getDate")); }); //handle disposal (if KO removes by the template binding) ko.utils.domNodeDisposal.addDisposeCallback(element, function() { $el.datepicker("destroy"); }); }, update: function(element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), $el = $(element); //handle date data coming via json from Microsoft if (String(value).indexOf('/Date(') == 0) { value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1"))); } var current = $el.datepicker("getDate"); if (value - current !== 0) { $el.datepicker("setDate", value); } } }; 

我已经添加了两个对应于我想要修改的选项的处理程序:

 ko.bindingHandlers.minDate = { update: function(element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), current = $(element).datepicker("option", "minDate", value); } }; ko.bindingHandlers.maxDate = { update: function(element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), current = $(element).datepicker("option", "maxDate", value); } }; 

并在我的模板中使用它们:

 <input data-bind="datepicker: selectedLowerValue, datepickerOptions: { minDate: minValue()}, maxDate: selectedUpperValue" /> <input data-bind="datepicker: selectedUpperValue, datepickerOptions: { maxDate: maxValue()}, minDate: selectedLowerValue" /> 

使用以前答案中提供的自定义绑定并不总是可能的。 调用$(element).datepicker(...)需要相当长的时间,如果你有,例如,几十甚至几百个元素来调用这个方法,你必须做“懒惰”,即一经请求。

例如,视图模型可以被初始化, input被插入到DOM中,但是相应的dateselect器只会在用户点击时被初始化。

所以,这是我的解决scheme:

添加允许将任意数据附加到节点的自定义绑定:

 KO.bindingHandlers.boundData = { init: function(element, __, allBindings) { element.boundData = allBindings.get('boundData'); } }; 

使用绑定来查看用于input值的observable:

 <input type='text' class='my-date-input' data-bind='textInput: myObservable, boundData: myObservable' /> 

最后,当初始化dateselect器时,使用它的onSelect选项:

 $('.my-date-input').datepicker({ onSelect: function(dateText) { this.myObservable(dateText); } //Other options }); 

这样,每当用户使用dateselect器更改date时,相应的Knockout observable也会更新。