我正在尝试将KnockoutJS与jQuery UI一起使用。我有一个带有日期选择器的输入元素。我目前正在运行knockout.debug.1.2.1.js
,似乎更改事件永远不会被Knockout捕获。元素如下所示:
<input type="text" class="date" data-bind="value: RedemptionExpiration"/>
我甚至尝试更改valueUpdate
事件类型,但无济于事。似乎Chrome在更改值之前会导致focus
事件,但IE不会。{/ p>
是否有一些“重新绑定所有绑定”的Knockout方法?从技术上讲,我只需要在将其发送回服务器之前更改值。所以我可以忍受这种解决方法。
我认为这个问题是datepicker的错,但我无法弄清楚如何解决这个问题。
有什么想法吗?
答案 0 :(得分:253)
我认为对于jQuery UI datepicker,最好使用一个自定义绑定,它将使用datepicker提供的API读取/写入Date对象。
绑定可能看起来像(来自我的回答here):
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/
答案 1 :(得分:13)
以下是RP Niemeyer的答案版本,该答案适用于此处的淘汰验证脚本: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);
}
}
};
更改事件处理程序的更改是先将输入的值而不是日期传递给验证脚本,然后仅将日期设置为observable(如果有效)。我还添加了自述绑定所需的validationCore.init:
http://github.com/ericmbarnard/Knockout-Validation/issues/69
我还添加了rpenrose关于改变模糊的建议,以消除一些令人讨厌的日期拣选方案妨碍事情发生。
答案 2 :(得分:11)
我使用了不同的方法。由于knockout.js似乎没有在更改时触发事件,因此我强制datepicker在关闭后调用其输入的change()。
$(".date").datepicker({
onClose: function() {
$(this).change(); // Forces re-validation
}
});
答案 3 :(得分:9)
尽管所有这些答案都为我节省了大量的工作,但它们都没有完全适合我。选择日期后,绑定的值不会更新。我只能在使用键盘更改日期值然后单击输入框时更新它。我通过使用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);
}
}
};
我怀疑放置了observable($(element).datepicker(“getDate”));在自己的函数中声明并使用options.onSelect注册它就可以了?
答案 4 :(得分:6)
感谢这篇文章,我发现它非常有用。
如果您希望DatePicker的行为与JQuery UI默认行为完全相同,我建议在更改事件处理程序中的元素上添加模糊:
即
//handle the field changing
ko.utils.registerEventHandler(element, "change", function () {
var observable = valueAccessor();
observable($(element).datepicker("getDate"));
$(element).blur();
});
答案 5 :(得分:3)
我通过更改包含的脚本文件的顺序解决了这个问题:
<script src="@Url.Content("~/Scripts/jquery-ui-1.10.2.custom.js")"></script>
<script src="@Url.Content("~/Scripts/knockout-2.2.1.js")"></script>
答案 6 :(得分:2)
与RP Niemeyer相同,但更好地支持WCF DateTime,Timezones和使用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);
}
}
};
享受:)
答案 7 :(得分:1)
我认为可以更容易地做到:<input data-bind="value: myDate, datepicker: myDate, datepickerOptions: {}" />
因此,您不需要在init函数中进行手动更改处理。
但在这种情况下,你的'myDate'变量只会获得可见值,而不是Date对象。
答案 8 :(得分:1)
或者,您可以在绑定中指定它:
更新:
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);
}
}
答案 9 :(得分:0)
根据Ryan的解决方案,myDate返回标准日期字符串,在我的情况下,这不是理想的日期字符串。我使用date.js来解析值,因此它将始终返回您想要的日期格式。看一下这个例子fiddle Example。
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"));
}
}
答案 10 :(得分:0)
我需要反复更新服务器上的数据,但是我的日期格式/日期(1224043200000)/我的日期格式/日期(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>
答案 11 :(得分:0)
很少有人要求动态的datepicker选项。在我的情况下,我需要一个动态日期范围 - 所以第一个输入定义第二个的最小值,第二个输入设置第一个的最大值。我通过扩展RP Niemeyer的处理程序解决了这个问题。所以对他原来的:
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" />
答案 12 :(得分:0)
使用先前答案中提供的自定义绑定并非总是可行。调用$(element).datepicker(...)
需要相当长的时间,如果你有几十个,甚至几百个元素来调用这个方法,你必须这样做&#34;懒惰&#34;,即on需求。
例如,可以初始化视图模型,将input
插入到DOM中,但只有在用户单击它们时才会初始化相应的日期选择器。
所以,这是我的解决方案:
添加允许将任意数据附加到节点的自定义绑定:
KO.bindingHandlers.boundData = {
init: function(element, __, allBindings) {
element.boundData = allBindings.get('boundData');
}
};
使用绑定来捕捉用于input
的值的可观察量:
<input type='text' class='my-date-input'
data-bind='textInput: myObservable, boundData: myObservable' />
最后,在初始化datepicker时,请使用它onSelect
选项:
$('.my-date-input').datepicker({
onSelect: function(dateText) {
this.myObservable(dateText);
}
//Other options
});
这样,每次用户使用datepicker更改日期时,相应的Knockout observable也会更新。