3

I have asked a similar question but didn’t get a real satisfying answer, so I will try again here. When I use code like this:

$("#element")   .on( 'click', function() {
                    // do something
                } )             
                .on( 'touchstart', function(e) {
                    e.preventDefault();
                    // do the same thing but on touch device like iPad f.e.
                    // and more over PLEASE do not fire the click event also!
                } );

I am expecting that the click event is never never never fired (because of the hierarchy with which browser should work through the events) but in fact when I touch the element let’s say 20 times, than one time the click event fires also. Why?

And I also tried things like:

$("#element")   .on( 'click', function() {
                    // do something
                } )             
                .on( 'touchstart', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    // do the same thing but on touch device like iPad f.e.
                    // and more over PLEASE do not fire the click event also!
                    return false;
                } );

It seemed to be a little more solid but not bulletproof. So I had to do:

 $("#element")  .on( 'click', function() {
                    if ( !touchdevice ) {
                        // do something
                    };
                } )             
                .on( 'touchstart', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    // do the same thing but on touch device like iPad f.e.
                    // and more over PLEASE do not fire the click event also!
                    return false;
                } );

which seems to work but is awfully silly, isn’t it? Anyone with ideas what is this about? Thanks!

EDIT: So I really had to do something like:

var touched;
$("#element")   .on( 'click', function() {
                    if ( !touched ) {
                        // do something
                    };
                } )             
                .on( 'touchstart', function(e) {
                    e.preventDefault();  // actual senseless here
                    e.stopPropagation(); // actual senseless here
                    touched = true;
                    // do the same thing but on touch device like iPad f.e.
                    // and more over PLEASE do not fire the click event also!
                    return false;        // actual senseless here
                } );

Come on guys! There must be a safe common way to use touchstart and click events on the same element ensuring that the click event is not fired (twice) to handle both touch sensible and regular browsers (or even the new combined ones). How would you do it?

Garavani
  • 755
  • 1
  • 13
  • 28
  • I think this could be related to http://stackoverflow.com/questions/27225577/how-to-prevent-ghost-clicks-on-hyperlinks-when-tapping-on-touch-device Try to see if the "click" happens when tapping just outside of the element. – aKzenT Dec 02 '14 at 22:35
  • Thanks for your comment! See my own answer to see what I am doing so far. – Garavani Dec 04 '14 at 07:47

2 Answers2

4

I am expecting that the click event is never never never fired (because of the hierarchy with which browser should work through the events) [...]

You have wrong expectations of even.preventDefault().

event.preventDefault() prevents the default action that the browser performs for that element/event combination. E.g. submitting a form or following link. It does not prevent any other event handler from being executed.

e.stopPropagation() prevents the event from bubbling up so that event handlers added to ancestors are not executed.


However, you cannot use any of these methods to prevent the handler of a different event to be executed, so setting a flag seems indeed to be the right way to do this.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Thanks Felix. Yet, 1) I read in some tutorials to do as code 1 from above to handle click and touch start events (on that one element only, obvious) together so that the handler is not executed twice (i.e. the click event ignored) 2) why does this combination work 20x i.e. click event not fired and only 1x not? Strange, isn’t it? 3) Is what I did in code 3 a „flag“. I thought it would be something different. Thanks for your patience and interest in clearing my thoughts! – Garavani Sep 05 '14 at 04:54
1

Right now I am using the following code in most places on my site which works very good and reliable:

var flag = false; 
$("#element").on( 'touchstart click', function() {
    if ( !flag ) {
        flag = true;
        setTimeout( function() {
            flag = false;
        }, 100 ); // someone else recommended 300 here but I use this value

        // action here

    };                
    return false;
} );

PS That is not my invention, but unfortunately I forgot the source because some time has passed.

Garavani
  • 755
  • 1
  • 13
  • 28
  • The source seems to be [this accepted answer](http://stackoverflow.com/questions/7018919/how-to-bind-touchstart-and-click-events-but-not-respond-to-both) to a similar question. I was able to find it after even more time has passed. – Martin Sep 28 '15 at 13:56