I'm trying to detect whether a click has occurred on a DatePicker control or not, but I can't accurately determine whether or not the event target element is a part of the DatePicker or not.
After a lot of debugging I've realized that the main issue is that pieces of the DatePicker are detached from the document, so they are simply not a child of any element.
Thanks to this other question I learned that the reason is that a chunk of the DatePicker is being removed and replaced when switching months, so the element that I get from event.target
is detached (it was part of the removed chunk).
So, what can I do to determine that this click happened within my control? I'm trying to write this agnostically of what kind of content is being used, although a specific fix for DatePickers would be ok.
So far what I've done is check if my elements contain a DatePicker, and whether the event target is detached. If so, I assume that the click happened on the DatePicker. This isn't perfect because there could be another DatePicker on the page. Also, the event target being detached doesn't necessarily have to be related to DatePicker.
Here's an example of what I have so far:
$(document).on("click", function (event) {
const stuff = $("something");
if (stuff.is($(event.target)))
return; // click was on stuff
if ($(event.target).closest(stuff).length)
return; // click was on descendents of stuff
if (stuff.is(":active, :focus"))
return; // stuff is active or focused
if (stuff.find(":active, :focus").length)
return; // a descendent of stuff is active or focused
if (stuff.is(".hasDatepicker") || stuff.find(".hasDatepicker").length) {
// stuff is or has a date picker
if (!$(event.target).closest($(document)).length) {
// event target is detached, and there's a date picker in stuff
// so have to assume click was on stuff's date picker
return;
}
}
// click was not within stuff's elements
}
What you are looking for is probably $(".selector").datepicker("widget")
Returns a jQuery object containing the datepicker. This method does not accept any arguments.
Code examples: Invoke the widget method:
var widget = $( ".selector" ).datepicker( "widget" );
Now that you can get the actual datepicker UI from the original element, you can use that how you like, ie to check if the click was on it.
Here is how I would solve this issue using the above:
$(function() {
$('#thedate').datepicker({
dateFormat: 'dd-mm-yy',
altField: '#thealtdate',
altFormat: 'yy-mm-dd'
});
$(document).on('mousedown',function(event) {
// only evaluate if the click was NOT on the element or any of its descendants
if (!$(event.target).closest('#some-container').length && !$(event.target).is('#some-container')) {
// now lets check for any elements in our container that have datepickers
var $contanier = $('#some-container');
var $elementsWithDatePickers = $contanier.find('.hasDatepicker');
var clickedChildDatePicker = false;
$elementsWithDatePickers.each(function() {
// for each datepicker found, check that the click was also not on it or any of its descendants
var $widget = $(this).datepicker("widget");
if ($(event.target).is($widget) || $(event.target).closest($widget[0]).length > 0) {
clickedChildDatePicker = true;
return false;
}
});
if (!clickedChildDatePicker) {
$contanier.hide();
}
}
})
});
#other{
background-color:#ccc;
padding: 45px;
}
#some-container{
background-color:#fff;
padding: 45px;
}
<link href="https://code.jquery.com/ui/1.8.21/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<div id="other">
<div id="some-container">
Date :
<div id="thedate">
</div>
<br />
</div>
click here to hide container
</div>