I am using Bootstrap 3 Datepicker to edit the date and time of one of the properties of my observable. It works fine when I am creating a new record but not to edit one that is already created.
My custom binding is as follows
ko.bindingHandlers.datetimepicker = {
init: function (element, valueAccessor, allBindings) {
var options = {
format: 'DD/MM/YYYY hh:mm A',
locale: 'en-AU',
sideBySide: true,
defaultDate: ko.unwrap(valueAccessor())
};
ko.utils.extend(options, allBindings.dateTimePickerOptions);
$(element).datetimepicker(options).on("dp.change", function (evntObj) {
var observable = valueAccessor();
if (evntObj.timeStamp !== undefined) {
var picker = $(this).data("DateTimePicker");
var d = picker.date();
if (ko.isObservable(observable)) {
observable(d.format(options.format));
} else {
valueAccessor(d.format(options.format));
console.log("Not observable");
}
console.log(observable, "\n", $(element).val());
}
});
},
update: function (element, valueAccessor) {
var value = ko.unwrap(valueAccessor());
$(element).datetimepicker('date', value || '');
}
};
And here is the relevant part of my ViewModel
var PicksViewModel = function () {
var self = this;
self.pick = ko.observable();
self.newPick = {
Title: ko.observable(),
Sport: ko.observable(),
MatchTime: ko.observable(),
PublishTime: ko.observable(),
HomeTeam: ko.observable(),
AwayTeam: ko.observable(),
Analysis: ko.observable(),
PickSummary: ko.observable()
};
}
newPick
and pick
are used for 2 separate forms. One to create a new one and one to edit an existing pick. When I use the datepicker for a new pick it works as intended and I don't get a console log that says Not observable
but when I edit an existing pick the observable isn't passed to the binding and therefore doesn't get updated and I get the console log.
I am using the following html for my binding
<form data-bind="with:pick">
<!-- Rest of form omitted -->
<div class="input-group date" id="editMatchTimePicker">
<input type="text" data-bind="datetimepicker:MatchTime">
</div>
</form>
Update
I fixed it by binding to a separate observable and using a computed observable to handle the conversion between UTC and local times.
self.editMatchTime = ko.observable();
self.localMatchTime = ko.pureComputed({
read: function () {
self.editMatchTime(self.pick().MatchTime);
var local = moment.utc(self.pick().MatchTime).local().format("YYYY-MM-DD[T]HH:mm:ss");
return local;
},
write: function(value) {
var utcTime = moment(value).utc();
self.editMatchTime(utcTime);
},
owner: self
});
And then my binding changed to
<input type="text" data-bind="datetimepicker:$root.localMatchTime">
You're not binding an observable to your datetimepicker
, you're binding a value which is converted from the observable MatchTime
. You could bind MatchTime
itself and do the conversion inside the handler, or you can use the allBindings
parameter to get at the value
-bound observable. If you bind the observable itself, you can roll the value
-binding functionality into your custom binding handlers so that you only have to make one binding. (See the "Simple Wrapper Binding" section here.)