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

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.
    }
});

This code from @Krishna doesn't work for me:

$('.button').on('touchstart click', function(e) {    
    e.stopPropagation(); //stops propagation
    if(e.type == "touchstart") {
        // Handle touchstart event.
    } else if(e.type == "click") {
        // Handle click event.
    }
});

But this one should work, as @Slashback originally suggested.

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

    if(e.type == "touchstart") {
        // Handle touchstart event.
    } else if(e.type == "click") {
        // Handle click event.
    }
});

.preventDefault() alone worked for me instead of .stopPropagation(). I din't have to do the overkill as well.


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.

Tags:

Jquery

Mobile