Conflicts between double tap and click. (jQuery and Hammer.js)

Asked

Viewed 241 times

3

I’m trying something different, I would like to implement something similar to an Instagram feature: two tapas to give like.

To try this, I am using the latest versions of jQuery and Hammer.js. I am not an advanced programmer in this area, however I have come to the following logic to identify which event the user wants to run:

var postDoubleTapped;
postDoubleTapped = false;

Hammer($('.post').get(0)).on('doubletap', function() {
  event.preventDefault();
  postDoubleTapped = true;

  console.log('Double tap!');
  return false;
});

$(document).on('click', '.post a', function(event) {
  event.preventDefault();
  console.log(postDoubleTapped);

  setTimeout((function(_this) {
    return function() {
      if (!postDoubleTapped) {
        location.href = $(_this).attr('href');
      }
      postDoubleTapped = false;
    };
  })(this), 500);
  return false;
});

As you can see in the example (http://codepen.io/caio/pen/vqEjc), didn’t work! The console returns:

Console

There’s another problem, I can’t reproduce the target="_blank" on the tag a.

Is this the best method to do this? Am I on the right track? How can I fix this?

1 answer

1

Your problem is that the setTimeout is called twice: once in the first click/slap and once in the second. What is being returned on the console is natural: 1) the first is detected, prints false and creates a setTimeout; 2) the Hammer treats of doubletap, printing Double tap!; 3) the second is detected, prints true and creates a new setTimeout.

The first setTimeout executes, assigning postDoubleTapped again to false. When the second setTimeout execute, this variable already has value false, so that it does the redirect.

To solve the problem, let’s go in pieces:

  1. For a quick fix, save the return value of setTimeout a variable and - before creating another - destroy it using clearTimeout:

    var ultimoTimeout = null;
    
    ...
    
    $(document).on('click', '.post a', function(event) {
        event.preventDefault();
        console.log(postDoubleTapped);
    
        if ( ultimoTimeout !== null )
            clearTimeout(ultimoTimeout);
        ultimoTimeout = setTimeout((function(_this) {
            ...
    
  2. For a "correct" solution, the interesting thing would be to prevent the event treated by Hammer to propagate. First, I noticed that you are using the event instead of taking the function parameter, but I don’t think it made a difference in practice:

    Hammer($('.post').get(0)).on('doubletap', function() {
    
    // Não deveria ser:
    //Hammer($('.post').get(0)).on('doubletap', function(event) {
    

    Besides, you call the preventDefault, but not the stopPropagation (that yes should prevent the event from propagating - getting to be treated by jQuery). I say "should" because - for some reason I don’t know - using it doesn’t seem to have made a difference... I noticed that the target of the event dealt with by Hammer is the image, not the hyperlink, but it shouldn’t matter - since the image is within link. I don’t understand what’s going on, so that a workaround would use the solution proposed in item 1.

  3. Finally, it doesn’t matter if your link has target="_blank" or not, since you are doing - via Javascript - a redial of the current window to the new address (but this you had already noticed, right?). The solution is to use window.open instead of touching the location.href:

    if (!postDoubleTapped) {
        window.open($(_this).attr('href'), $(_this).attr('target') || "_self");
    }
    

    This will make the browser try to open the URL in the window specified by the attribute target of your link (in case, _blank) or - if this attribute does not exist - in the window itself (_self). In my test, Chrome blocked the redirect (as if it were a popup) and - according to that question on Soen - there’s not much you can do about it...

    From what I read, the problem is in the setTimeout - if the opening of the window was a direct consequence of the user’s click (i.e. occurred while the click event itself was being processed) then I believe that the browser would open normally. But how it occurs in an arbitrary moment (when the setTimeout executes) the popup blocker thinks the site tried to open a window on its own, and does not. In that regard, I’m afraid I have nothing to suggest for now...

  • 1

    Additional information: that question on Soen suggests using window.stop in the ondblclick to stop page switching, but I believe it only works (if it works) on the current page. That other proposes an alternative, however as the behavior is similar to that of a "pop under" (i.e. more used "pro mal" than "pro bem") many browsers do not allow it (in Chrome, for example, it did not work). Finally, here it is an argument discouraging such use.

  • Thank you so much for your help, I am considering all your observations and trying to rebuild my code (stopping using Hammer.js may even be an option). In item 2 you said about the target of Hammer. This does not happen because they are different selectors in events?

  • @Caiotarifa I don’t understand enough DOM events to know why this happens (because the $('.post').get(0) on the Hammer selector also refers to the hyperlink), but I know it shouldn’t matter: events on img propagate pro a, propagating pro .post until you reach the document (where he is treated by on jQuery). This all occurs "behind the scenes" - independent of the framework/library - so I was rather surprised when the stopPropagation didn’t work...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.