75

I've got a sub-nav that works using jquery - A user clicks on the top level list item, for instance 'services' which triggers the dropdown. The dropdown toggles via clicking the 'service' link. I've made it so a user can click anywhere on the screen to toggle the dropdown to a closed state. But as the site is responsive i want the user to be able to click (touch) anywhere on the screen to close the dropdown but my problem is that it's not working on the touch devices.

My code ive setup for the document click is:

$(document).click(function(event) { 

  if ( $(".children").is(":visible")) {
    $("ul.children").slideUp('slow');
  }

});

I'm assuming document.click might not work on touch devices, and if not, what work-around is there to achieve the same effect?

Thanks

Gruber
  • 2,196
  • 5
  • 28
  • 50
Gerico
  • 5,079
  • 14
  • 44
  • 85
  • Try attaching the click event to `$('html')` or `$('body')` instead. – millimoose Jul 09 '12 at 14:30
  • just include cursor:pointer it will work [enter link description here](https://stackoverflow.com/questions/3025348/how-do-i-use-jquery-for-click-event-in-iphone-web-application/4910962#4910962) Thanks to :-> – Devika B Oct 15 '19 at 07:00

6 Answers6

181

Update! In modern browsers, the click event will be fired for a tap, so you don't need to add extra touchstart or touchend events as click should suffice.

This previous answer worked for a time with browsers that thought a tap was special. It originally included a "touch" event that actually was never standardised.

Unless you have a problem with:

$(document).on('click', function () { ... });

There is no need to change anything!

Previous information, updated to remove touch...

To trigger the function with click or touch, you could change this:

$(document).click( function () {

To this:

$(document).on('click touchstart', function () {

The touchstart event fires as soon as an element is touched, so it may be more appropriate to use touchend depending on your circumstances.

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 8
    Probably 'touch' is better than 'touchstart'. Of course it depends, but touchstart can cause weird behaviour of our application (for example when we display popup, close it on touchstart - and the touch event will be propagated then to the elements underneath). – Szorstki Apr 15 '14 at 09:25
  • perhaps this answer can be changed to incorporate `touch` in place of `touchstart`, as per the comment by @Szorstki. – alexwc_ Aug 30 '16 at 02:07
  • 4
    In my case I found "touch" didn't work (closing drop-down menus by tapping elsewhere). Tapping on the document does not fire a touch event on my current iPad. Only touchstart did the job. –  Mar 25 '17 at 06:09
  • 1
    there is also **tap** event – Muneeb Mirza Jan 02 '18 at 08:08
  • I find no official documentation on any DOM event called touch. All I can see is touchend, touchstart, touchcancel and touchmove. Can you @Fenton refer to some documents confirming the existance of this event. My guess would be that in your case it works because you added click and touch, so click is the actual event being used...? – Wilt Mar 23 '21 at 08:53
  • @Wilt thanks for highlighting this old post! Not only does `touch` not exist any longer, you also don't need to do anything as modern browsers will trigger `click` on tap. – Fenton Mar 24 '21 at 14:06
53

touchstart or touchend are not good, because if you scroll the page, the device do stuff. So, if I want close a window with tap or click outside the element, and scroll the window, I've done:

$(document).on('touchstart', function() {
    documentClick = true;
});
$(document).on('touchmove', function() {
    documentClick = false;
});
$(document).on('click touchend', function(event) {
    if (event.type == "click") documentClick = true;
    if (documentClick){
        doStuff();
    }
 });
ale
  • 546
  • 4
  • 8
4

can you use jqTouch or jquery mobile ? there it's much easier to handle touch events. If not then you need to simulate click on touch device, follow this articles:

iphone-touch-events-in-javascript

A touch demo

More in this thread

Community
  • 1
  • 1
SSA
  • 5,433
  • 4
  • 36
  • 50
2

To apply it everywhere, you could do something like

$('body').on('click', function() {
   if($('.children').is(':visible')) {
      $('ul.children').slideUp('slow');
   }
});
ayyp
  • 6,590
  • 4
  • 33
  • 47
  • 1
    I thought this would work fine, however on the iphone / ipad it doesn't seem to work. I'm looking into Jquery mobile but i would like to avoid adding it in – Gerico Jul 10 '12 at 13:26
  • @Mat-visual Take a look at `.bind()` and `.unbind()` for click events. I ran into the same problem as well. – ayyp Jul 10 '12 at 13:35
  • Yeh i was looking along those lines. i just tried $(document).bind('click', function() { - but still not luck for some odd reason. I must be missing something, perhaps a conflict. Works fine on normal pc browsers though – Gerico Jul 10 '12 at 13:43
  • @Mat-visual I got around it by doing something like `function bindTap() { $('element').bind("click", function(e){} ); $("element").click(function(){ //DO SOMETHING $("element").unbind("click"); }); }` And then calling the function on a click event somewhere. The problem with `.click` on iOS is that it unbinds the click event. – ayyp Jul 10 '12 at 14:37
  • 1
    I think your definitely on to something i will play around, see if i can get it working, thanks, and i will let you know if it's successful. – Gerico Jul 11 '12 at 07:58
2

As stated above, using 'click touchstart' will get the desired result. If you console.log(e) your clicks though, you may find that when jquery recognizes touch as a click - you will get 2 actions from click and touchstart. The solution bellow worked for me.

//if its a mobile device use 'touchstart'
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
    deviceEventType = 'touchstart'
} else {
//If its not a mobile device use 'click'
    deviceEventType = 'click'
}

$(document).on(specialEventType, function(e){
    //code here
});
2

the approved answer does not include the essential return false to prevent touchstart from calling click if click is implemented which will result in running the handler twoce.

do:

$(btn).on('click touchstart', e => { 
   your code ...
   return false; 
});
kofifus
  • 17,260
  • 17
  • 99
  • 173