I'm trying to create a knockout binding for Flatpickr but having no luck. I've tried tweaking the code from the accepted answer here to no avail. The Flatpickr is initialized, but it doesn't seem to use the default options I have setup, and the update part of the binding just doesn't work at all.
My code is below. I would create a jsFiddle but it is blocked here at work..
ko.bindingHandlers.datetimepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().datetimepickerOptions || { dateFormat: 'm-d-Y', enableTime: true };
var $el = $(element);
$(element).flatpickr(options);
//handle the field changing by registering datepicker's changeDate event
ko.utils.registerEventHandler(element, "onChange", function () {
var observable = valueAccessor();
observable($el.val());
});
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$el.flatpickr("destroy");
});
$el.val(new Date(ko.utils.unwrapObservable(valueAccessor())));
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var $el = $(element);
// handle json date from microsoft
if (String(value).indexOf('/Date(') == 0) {
value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1")));
}
var current = new Date($el.val());
if (value - current !== 0) {
$el.flatpickr('setDate', value);
}
}
};
EDIT
A little more info on my situation. I have a page with pager buttons at the top, and these buttons cycle through an array in my viewmodel. Every time I page, a displayedRecord property gets set to the next/prev item in the array, and all the edit fields are bound to the displayedRecord property. This works fine for all my inputs except the ones that use datetimepicker binding that @atitsbest provided to me.
The datetimepicker fields get populated the first time, but once I page past them the viewmodel property for that record somehow gets set to null.
EDIT 2
Got this working finally. Here's the final product. Ended up removing the subscribe in the init function because it caused errors when trying to set it's observable to null. Also added flatpickr wrap functionality for user's to provide their own buttons for clearing, toggling, etc.
ko.bindingHandlers.flatpickr = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = $.extend({
dateFormat: 'm/d/Y H:i',
enableTime: true,
time_24hr: true,
minuteIncrement: 1
}, allBindingsAccessor().flatpickrOptions);
var $el = $(element);
var picker;
if (options.wrap) {
picker = new Flatpickr(element.parentNode, options);
} else {
picker = new Flatpickr(element, options);
}
// Save instance for update method.
$el.data('datetimepickr_inst', picker);
// handle the field changing by registering datepicker's changeDate event
ko.utils.registerEventHandler(element, "change", function () {
valueAccessor()(picker.parseDate($el.val()));
});
// handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$el.flatpickr("destroy");
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
// Get datepickr instance.
var picker = $(element).data('datetimepickr_inst');
picker.setDate(ko.unwrap(valueAccessor()));
}
};