I\'ve got a jQuery datepicker that is working great for me, except when I fresh the content via ajax, I lose the datepicker. From what I can tell I should be using jQuery on
The jQuery .on()
function is for deferred event handling, but it doesn't work for plugin initialization.
It works for events because the DOM model propagates events from DOM elements to their parent elements, all the way to the top. So when you click on a link, you're also clicking on whatever contains that link (a div
for example), whatever contains that container, and so on all the way up to the body
tag and eventually the document
itself. .on()
takes advantage of this by binding to the click event of a common parent element instead of the dynamic child elements, so child elements can be added/removed without losing the event handler on the parent.
Plugin initialization doesn't work this way, though. In order to initialize a plugin on a target element, it must be done on the element itself which means the element needs to be in the DOM at the time. Thus, when you add new elements dynamically, you need to target those new elements and initialize the plugin on them. So your success
function from the AJAX call would need to do that.
Note that since your AJAX call is itself inside of your initialization, you're going to need to split some of these out into separate functions for re-use. Otherwise this re-initialization would nest inside itself indefinitely.
Maybe something like this:
var datePickerClose = function (dateText, inst) {
var selectedDate = $(this).datepicker("getDate"); //Date object
$.ajax({
url: "/url",
dataType: "json",
method: 'post',
data: {
value: selectedDate.toDateString() + ' ' + selectedDate.toTimeString()
},
beforeSend: function () {
$("#loading").fadeIn();
},
success: function (data, textStatus) {
$("#content").html(data);
$("#content").find("[id^=startPicker]").each(function () {
bindDatePicker(this);
});
},
complete: function () {
$("#loading").fadeOut();
}
});
};
var bindDatePicker = function(element) {
$(element).datetimepicker({
showOn: "button",
buttonImage: "/img/calendar_icon.png",
buttonImageOnly: true,
dateFormat: 'mm/dd/yy',
timeFormat: 'hh:mm tt',
stepMinute: 1,
onClose: datePickerClose
});
};
$("[id^=startPicker]").each(function() {
bindDatePicker(this);
});
This is, of course, free-hand untested code just to demonstrate the concept. It may require a little tweaking, and there may be a more elegant way to accomplish the same logic.
I've got a similiar problem: After an ajax page reload I can't set new datepicker with $(element).datepicker(). Because Datepicker only does once a clean initialization, I just set directly after ajax success:
$.datepicker.initialized = false;
Now the next $(element).datepicker() will cause a fresh initialization. This affects all datepicker on the side, so you may have reset datpicker outside the ajax-container.
You can not delegate plugin, delegation is for event listener only. Use the success callback function and reinitailize datepicker plugin once targeted element is added
success: function (data, textStatus) {
$("#content").html(data).find('[id^=startPicker]').datepicker({...});
},
Actually, the simplest way I have found to do this is by simply putting the bind code within the success function like so: ELEMENT.datepicker();
.
Eg: $('.datepicker').datepicker();
Full code:
$('#loaddetails').on('click',function(){
//Run ajax fetch here
$.ajax({
type: "POST",
url: "yourlink",
data: $('form').serialize(), // serializes the form's elements.
dataType: 'json',
beforeSend: function () {
console.log('Form serialised');
$('#status').html('<img src="../img/spinner.gif" width="16" height="16">');
},
success: function(data)
{
$('#status').html(data);
$('.datepicker').datepicker();
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
console.log("All ok");
return false;
});