Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing ghost click when binding 'touchstart' and 'click'

Tags:

jquery

mobile

I'm developing an app, testing on my desktop and mobile. I am trying to fix these slow button presses on the mobile, and just learned about the difference between touchstart and click.

So I bound my buttons with jquery to perform both touchstart and click like so:

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

Now the app is performing slightly better on the phone. However, it is performing a touch click, and then a regular click, ie potentially double clicks, or when the next slide comes in, it clicks on something there. In my case a form is appearing, and the input field that appears in the space where the button clicked was, is selected. Ghost click.

How can I tell my function that if there is a touch, ignore the click?

Or better yet, is there a way to tell jquery to just acknowledge all 'clicks' as touches?

I would remove the 'click' binding, but then I can't exactly test in my desktop environment so easily.

like image 528
willdanceforfun Avatar asked Nov 26 '13 18:11

willdanceforfun


2 Answers

If you want to do specific stuff for different event types use e.type

$('.button').on('touchstart click', function(e) {    
    e.preventDefault(); //prevent default behavior
    if(e.type == "touchstart") {
        // Handle touchstart event.
    } else if(e.type == "click") {
        // Handle click event.
    }
});
like image 193
Venkata Krishna Avatar answered Sep 30 '22 21:09

Venkata Krishna


Touchstart should happen before click, so I remove the click handler if the event is of type touchstart. This seems to be working nicely for my purposes:

$('.do-popdown').on('click touchstart', handlePopdown);
function handlePopdown(e){
    if(e.type == 'touchstart') {
        $('.do-popdown').off('click', handlePopdown).click(function(e){
            // do nothing
            e.stopPropagation();
            e.preventDefault();
            return false;
        });
    }
    // do my handling...
    // and nothing else:
    e.stopPropagation();
    e.preventDefault();
    return false;
}

The e.stopPropagation(); e.preventDefault(); return false; may be overkill, but I use this on a variety of different elements (<a>, <div>, <span>, <button>, &c.) and this meets my usual needs.

EDIT: A more general (better?) approach is to create something similar to the familiar .click() event binder:

jQuery.fn.extend({
    clickOrTouch: function(handler) {
        return this.each(function() {
            var event = ('ontouchstart' in document) ? 'touchstart' : 'click';
            $(this).on(event, handler);
        });
    }
});

This way, only the appropriate event is attached to the selected element(s).

I suppose a more "proper" name would be .touchstartOrClick() but since it is more or less a replacement for .click() I decided to start the name with click.

This can be used just like .click(). For example, put a button inside of a div and run:

$('button').clickOrTouch(doSomething);
$('div').clickOrTouch(doSomething);
function doSomething(e) {
    $('body').append(this.tagName + ' ' + e.type + '<br>');
    e.stopPropagation();
}

This will show "DIV click" or "BUTTON touchstart" depending on how it is triggered. If this is used on a link, add e.preventDefault() if needed in your handler.

like image 44
Slashback Avatar answered Sep 30 '22 22:09

Slashback