Reputation: 14995
I am working on binding both the date and the time to two separate controls using Knockout and HTML5 elements. Each of the binding is working independent of the other, but I am struggling to get them to update / display the same values of their respective portions of the property (date show date, time show time of same day)
I used the datepicker from jQuery and RP's custom binding handler and I can bind to the HTML5 time input element but I am having a problem on updating the date observable properly when you change the time -
http://jsfiddle.net/NAgNV/1263/
The problem appears to be here -
ko.utils.registerEventHandler(element, "change", function() {
var observable = valueAccessor();
console.log($(element).value);
observable($(element).value);
});
If I select the first object in the array (why is it returning an array?) like this - $(element)[0].valueAsDate
it appears to update the observable, but oddly enough it changes the date to 1970 and doesn't update the datepicker.
EDIT
So I have been using this in a production application with no problems until this weekend - on Saturday oddly enough it started to decrement the hour every time you changed anything in the time picker. Check out the example for proof -
http://jsfiddle.net/NAgNV/1339/
What changed? Get ready for this one...
The adjusted time is being set as the time on January 1st, 1970. The adjusted date is correctly set to the proper date. When the date picker is set to any day that is Central Standard Time, no problem. When it is Central Daylight Time it starts going nuts. The problem is that getting the time from one time zone and setting it to the value of another time zone decrements the hour.
It also makes it impossible to set the time by manually typing it in.
I updated Joseph's answer below and awarded the bounty since he put in extra time up front anyway
Upvotes: 0
Views: 2338
Reputation: 8520
An HTML Input type='time' will only contain the time portion - no date. So when reading the change, you'll need to set the just time part on the existing date observable, instead of taking the value as a complete date.
Note that valueAsDate
will give you the date, but it does so without adjusting for timezone. E.g. "11:04" in an HTML5 input might translate to "6:04" once converted to date, assuming GMT -5.
Here's some code that should make this work correctly. I would recommend implementing some knockout throttling
to improve the performance of the time selector.
//handle the field changing
ko.utils.registerEventHandler(element, "change", function () {
var observable = valueAccessor();
console.log('observable - ', observable());
var tzdstOffset = (observable().getTimezoneOffset() + (moment(observable()).isDST() ? 60 : 0));
var adjustedTime = new Date($(element)[0].valueAsDate.getTime() + (tzdstOffset * 60 * 1000));
var adjustedDate = observable();
adjustedDate.setHours(
adjustedTime.getHours(),
adjustedTime.getMinutes(),
adjustedTime.getSeconds()
);
observable(adjustedDate);
});
P.S. The array comes from the jQuery selector. Selecting DOM elements using jQuery will always result in an array with zero or more elements. The items in the array are the underlying DOM elements.
Upvotes: 1