Recently, I encountered an issue on jQuery Datepicker that occurs only on IOS devices. The issue happens when a user taps anywhere the document body outside of the datepicker control, the calendar modal won’t get hidden once showed. It took me a while to figure out the cause of this issue. The problem was IOS devices do not fire a “click” event but rather a “touch” event when the user taps on the device’s screen. A click involves a mouse while a tap doesn’t. This is a significant difference to take note.
To solve the issue, my first approach was to write a script binding “ontouchstart” event on the document’s body then hide the calendar modal through DOM manipulation. However, I find this solution to be complicated and unreliable. What if someone changed the id of the datepicker control? Another thing is I ended up writing more lines of code. This won’t work since a lot of pages in the project were using the widget. A global fix is the best approach. So I browsed inside datepicker’s source code (v1.12.0) and found this function starting line 965,
_checkExternalClick: function( event ) {
if ( !$.datepicker._curInst ) {
return;
}
var $target = $( event.target ),
inst = $.datepicker._getInst( $target[ 0 ] );
if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
!$target.hasClass( $.datepicker.markerClassName ) &&
!$target.closest( "." + $.datepicker._triggerClass ).length &&
$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
$.datepicker._hideDatepicker();
},
The function basically listens to any click events outside the datepicker widget. Once verified that the click event’s target is outside the widget’s boundary, it will hide the shown modal calendar. Another search on the function’s instance brought me to this line ( line 2087 ),
/* Initialise the date picker. */
$( document ).on( "mousedown", $.datepicker._checkExternalClick );
Thus, I concluded that the datepicker widget only listens to “mousedown” event. The user needs a mouse to click in order for the “_checkExternalClick” function to be called. We can see that the best solution for my situation is to add a “touchstart” event on line 2087. Hence a simple fix to this issue.
/* Initialise the date picker. */
$( document ).on( "mousedown touchstart", $.datepicker._checkExternalClick );