• # March 19, 2017 at 3:25 am

    Never mind this one, I’ll check the code again first.
    For now I can’t see straight anymore…

    # March 19, 2017 at 5:56 am

    For now I can’t see straight anymore…

    Still enough to not stop, I suppose. :-/

    But this one’s rather nice…

    $('div').on('touchstart click', {flag: false}, function(e) {
    if (e.type == 'click' && return; = e.type == 'touchstart';
    //do stuff on either event

    Even though it doesn’t reset, which would be convenient with devices that support both.

    Now I’m calling it a day…

    $('div').on('touchstart touchcancel click', {flag: false}, function(e) {
      if (e.type == 'touchcancel' || e.type == 'click' && { = false;
  = e.type == 'touchstart';
      //do stuff on either event
    # March 19, 2017 at 10:51 pm

    I’ve heard that this solution from Stackoverflow takes care of the ghost click:

    $(document).on('touchstart click', '.myBtn', function(event){
        if(event.handled === false) return
        event.handled = true;
        // Do your magic here

    Looks like that was extracted from some jsbin code:

    That doesn’t seem to work either, at least not with Firefox touch emulation. Even though using a flag at all doesn’t seem necessary when preventDefault is also in place…

    var kind;
    function TouchClick(sel, fnc) {
      $(sel).on('touchstart click', function(event) {
        $('div span').append(event.handled + '<br>');
        if (event.handled !== true) {
          kind = event.type;
          event.handled = true;
        } else {
          return false;
    TouchClick('div', function() {
      $('div span').append(kind + '<br>');

    Here event.handled is just as undefined on each occurence as with the smaller script.

    # March 20, 2017 at 5:30 am

    Hehe thanks for continuing to work on this… did you try adding the css property?

    # March 20, 2017 at 9:47 am

    That’s a new concept for me so I’m still reading up on it. :-)
    Googling a bit and landing on jQuery event data was a nice find too…

    I’m usually quite relentless when trying to get to the bottom of some code.
    Often up to a point where I tire myself (and maybe even others) majorly. :-/

    # March 20, 2017 at 10:05 am

    Feel free to in return incorporate any of my fiddling-findings if you think it might enhance your own SO answer by the way, Mottie… the format there is of a wiki community after all. With 32 existing answers, I definitely won’t be adding one myself.

    # March 20, 2017 at 10:56 am

    Well actually that question/answer on SO is about binding to touch & click events, not really about ghost clicks. I think you should find a question and add an answer there since you’re doing all this work – I’d up-vote you!… or at least write up a blog post somewhere and share a link here.

    # March 20, 2017 at 12:15 pm

    I think the code at the top is what the other answer was intended to be but with all the details discussed in the comments, yours does look quite complete.

    There was an underwhelming topic on SO where someone asked how to switch between touch and mouse. It already having an accepted answer, I suggested to listen to both by posting some rather crude and flawed code. Quite a while later someone found and upvoted this so I felt obliged to at least post a bug free version. That’s enough for me.

    It’ll be a while before I turn the last stone on this and come up with the most ideal code…

    # March 22, 2017 at 7:02 am

    Okay, small edits don’t seem to be allowed… let me post again.

    Original “ghost click” issue – an old Android bug, sort of solved…

    But here’s the final code I’m using to create a page:tap, eliminating the more commonly known ghost click that comes from touch events being emulated:

    function swiftClick(aim) {
      $(document).on('mousedown touchstart click', aim, {}, function(e) {
        var mean = $(e.currentTarget), info =;
        if (e.type == 'mousedown' && (e.which != 1 || info.hit)) return;
        if (e.type == 'click') {
          delete info.hit;
          return false;
        info.peg =;
   'mouseup touchend', function(e) {
          if (e.type == 'touchend') info.hit = true;
          else if (info.hit) return;
          if ( > 300) return;
      .on('page:tap', aim, function() {
        if ($(this).is('a')) location = this.href;


    $('.something').on('page:tap', function() { // do whatever });

    Using persistent event data’s a bit nicer than adding classes. Clicks on links will have their default behaviour blocked and get redirected by the script. Subsequent touchstart-touchend or mousedown-mouseup will not trigger a page:tap if it took longer than 300ms.

    It’s going a bit out of the scope of the original issue but the custom event I put together has a shortcoming as well that is in the same sphere. Which is that if you happen to touch an element with the event listener and start scrolling, after removing the finger the event might get triggered.

    In fact, default touchcancel behaviour on many browsers will make the touchend not fire in that case which is quite convenient. But the 300ms time limit should also mostly solve it.

Viewing 9 posts - 16 through 24 (of 24 total)

You must be logged in to reply to this topic.