knockoutjs привязка данных с помощью jquery-ui datepicker
Я использую JQuery UI DatePicker. Поле ввода HTML позади него в настоящее время подключено к KnockoutJS как зависящий от объекта, но когда его значение задается в модели представления, средство выбора даты теряет свой формат.
Как мне это сделать и не потерять формат? Я бы хотел, чтобы viewModel не знал, что это jQuery datepicker.
7 ответов
Вы можете написать пользовательскую привязку, которая устанавливает дату в поле, используя API DatePicker, а также устанавливает значение вашей наблюдаемой, читая дату правильно.
Пользовательская привязка может выглядеть так:
ko.bindingHandlers.datepicker = {
init: function(element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().datepickerOptions || {},
$el = $(element);
//initialize datepicker with some optional options
$el.datepicker(options);
//handle the field changing
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),
current = $el.datepicker("getDate");
if (value - current !== 0) {
$el.datepicker("setDate", value);
}
}
};
Вы бы использовали это как:
<input data-bind="datepicker: myDate, datepickerOptions: { minDate: new Date() }" />
datepickeroptions
будет необязательным и может включать в себя все, что вы хотите передать в datepicker()
вызов.
Кроме того, это предполагает, что вы используете наблюдаемую дату. Привязка должна выполнять немного больше работы, если вы хотите выполнить одностороннее связывание с ненаблюдаемым, но это маловероятно.
Пример здесь: http://jsfiddle.net/rniemeyer/NAgNV/
Мне пришлось немного изменить код RP Niemeyer для работы с моим кодом, используя опцию dateFormat, заменив
$(element).datepicker("getDate")
С
$(element).val()
Таким образом, отформатированная версия даты была передана правильно под капотом.
Я использовал код RP Niemeyer, помеченный как ответ выше, но так как я использовал его, я сделал несколько небольших изменений в нем. Я думал, что отправлю здесь. Может быть, это поможет другим. Это в значительной степени то же самое, единственное отличие состоит в том, что если элемент имеет значение при загрузке страницы, то он сохранит свое значение. Также я сделал $elem
переменная, так что будет меньше обработки $(element)
что jQuery должен будет сделать.
ko.bindingHandlers['jqDatePicker'] = {
'init': function(element, valueAccessor, allBindingsAccessor) {
/* Initialize datepicker with some optional options */
var options = allBindingsAccessor().jqDatePickerOptions || {},
prop = valueAccessor(),
$elem = $(element);
prop($elem.val());
$elem.datepicker(options);
/* Handle the field changing */
ko.utils.registerEventHandler(element, "change", function () {
prop($elem.datepicker("getDate"));
});
/* Handle disposal (if KO removes by the template binding) */
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$elem.datepicker("destroy");
});
},
'update': function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()),
$elem = $(element),
current = $elem.datepicker("getDate");
if (value - current !== 0) {
$elem.datepicker("setDate", value);
}
}
};
Вот то, что сработало для моих конкретных обстоятельств. Я использую достаточно новую версию MVC, которую сериализатор даты и времени по умолчанию отображает при ISO 8601 (см. "Кошмар, который является датами JSON. Плюс, JSON.NET и ASP.NET Web API)". Мои привязки записываются не непосредственно в средство выбора даты, а вместо этого в атрибут "значение" входного тега.
Также, к сведению, я использую date.js
ko.bindingHandlers.dateValue = {
update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
var value = valueAccessor(),
allBindings = allBindingsAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);
var pattern = allBindings.datePattern || 'MM/dd/yyyy';
var date = Date.parse(valueUnwrapped)
$(element).val(date.toString(pattern));
},
init: function(element, valueAccessor, allBindingsAccessor) {
//handle the field changing
ko.utils.registerEventHandler(element, "change", function () {
var observable = valueAccessor();
var date = Date.parse($(element).val());
observable(date.toString("yyyy-MM-ddThh:mm:ss"));
});
}
}
Привязка выглядит так:
<input class="date" type="text" data-bind="dateValue: SomeViewModelDate" />
И код JavaScript для включения средства выбора даты:
$(document).ready(function () {
$('.date').datepicker({ dateFormat: "mm/dd/yy" });
});
Приведенные выше примеры средства выбора даты изменяют формат даты в модели представления из формата WCF на формат даты JavaScript, когда пользователь выбирает новую дату в элементе управления datepicker.
В моем случае я передавал дату обратно службе WCF, и она не принимала десериализованную дату JavaScript, ей требовалась дата в формате WCF. Я изменил приведенный выше скрипт, чтобы он сохранял дату в модели представления в формате WCF, чтобы ее можно было отправить обратно на сервер в этом формате.
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).datepicker("getDate"));
// store the date in 'WCF String format"
var tempdate=$(element).datepicker("getDate");
var tempdatestr="/Date("+tempdate.getTime()+")/";
observable(tempdatestr);
});
//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);
}
}
};
Одно из решений заключается в том, чтобы отформатировать дату самостоятельно внутри функции absoluteObservable. Так что вы должны возвращать что-то вроде return viewModel.someOtherObservable()
в функции. Отформатируйте возвращаемое значение.
Если вы включите свой код, я могу объяснить больше.
Форматирование даты (в мм / дд / гггг) внутри зависимого наблюдателя - это именно то, что мне было интересно, как это сделать. Я выложу немного своего кода, если вы можете помочь, Питер Мортенсен и / или nEEBz.
<div data-bind="with: technology">
<div class="titleblock">
<label><b>End of Life Date</b></label>
<Input type="text" class="ui-datepicker" id="datepicker" data-bind="value: END_OF_LIFE_DATE"/>
</div>
</div>
во ViewModel - technologydetail.js:
var technology = ko.observable();
в Активировать:
return dataContext.getTechnologyById(currentTechnologyId, technology);
В текстовом поле отображается дата, которая выглядит следующим образом: ср 29 января 19:00:00 EST 2014, но я хочу, чтобы она просто отображалась: 29.01.2014. Я использую эту опцию datepicker - dateFormat: "mm/dd/yy", но это не влияет на отображаемое начальное значение.
Я смог отформатировать его, используя момент, и он прекрасно работает для отображения текущего значения базы данных, но, похоже, он нарушает привязку к наблюдаемой, потому что он больше не будет обновляться в SAVE.
<Input type="text" class="ui-datepicker" id="datepicker" data-bind="value: moment(END_OF_LIFE_DATE()).format('MM/DD/YYYY')" />