31

I have the following jquery event handling function:

$('.target').on('dblclick', function() {
    //respond to double click event
});

My issue is that this event handler doesn't work on touch devices (iPhone, iPad...). Can anyone recommend a reliable alternative to dblclick that works on touch devices and still allows comfortable double click use on full size devices?

vsync
  • 118,978
  • 58
  • 307
  • 400
JRulle
  • 7,448
  • 6
  • 39
  • 61

13 Answers13

36

I ended up building a custom double click function that will work on both mobile and desktop:

var touchtime = 0;
$(".target").on("click", function() {
    if (touchtime == 0) {
        // set first click
        touchtime = new Date().getTime();
    } else {
        // compare first click to this click and see if they occurred within double click threshold
        if (((new Date().getTime()) - touchtime) < 800) {
            // double click occurred
            alert("double clicked");
            touchtime = 0;
        } else {
            // not a double click so set as a new first click
            touchtime = new Date().getTime();
        }
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="target">Double click me</div>

Alternatively, here is the JSfiddle Demo.

JustCarty
  • 3,839
  • 5
  • 31
  • 51
JRulle
  • 7,448
  • 6
  • 39
  • 61
  • 1
    @matteo, for me it works on mobile, but it has some problems in detecting a single click after you already clicked once – Black Feb 12 '18 at 11:05
  • I found "pinch zoom" gestures triggered double clicks - at least on IOS. I used if ((now - touchtime) < 800 && (now - touchtime) > 150) to work around it... – paj Nov 28 '20 at 16:58
10

Add this to your index.html

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>

I found the mobile zoom function would throw off Jquery's dblclick. Basically it says your viewport wont change effectively shutting off the zoom. This works for me on my Nexus 5 running Chrome.

Thomas Valadez
  • 1,697
  • 2
  • 22
  • 27
  • Should that be user-scalable=no or are the two values identical? – Joel Roberts Jan 22 '17 at 23:33
  • Coool! This worked and also makes a lot of sense see my comment here in the accepted solution https://stackoverflow.com/questions/54828764/javascript-innertext-of-textarea-doesnt-reset-realoading-page – Robert Feb 22 '19 at 21:00
7

I know the question has been answered but thought it would be worth putting the solution I use all the time, cheers:

    var doubleClicked = false;
    $('.target').on('click', function() {   
        if (doubleClicked) {
            //do what you want to do on double click here
        }
        doubleClicked = true;
        setTimeout(() => {
            doubleClicked = false;
        }, 300);
    });
Luis Rita
  • 372
  • 3
  • 6
5

You can bind multiple event listeners on the element and use jQuery's tap event for the touch devices.

$( ".target" ).on({
  dbclick: function() {
    //do stuff
  }, touch: function() {
    //do the same stuff
  }
});
Aweary
  • 2,302
  • 17
  • 26
3

Thanks for the solution - the only thing I did was add a timeout so that they could be treated as separate events

var touchtime = 0;
var delay = 800;
var action = null;
$(".target").on("click", function() {
  /*Double Click */
  if((new Date().getTime() - touchtime) < delay){
     clearTimeout(action)
     alert('dbl');
     touchtime=0;
  }
  /* Single Click */
  else{
     touchtime = new Date().getTime();
     action = setTimeout(function(){
        alert('single');
     },delay);
  }
}));

Although I haven't tested it, might also be worth adding the following to a header section of any HTML <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/> as per: To "user-scalable=no" or not to "user-scalable=no"

Elliott de Launay
  • 1,027
  • 13
  • 31
2

The marked answer of @JRulle seems to work only for a single object, if u have many instances with the same class they will be considered as a single object see the example
Fiddle example

My solution seems to work in cases like that

var touchtime = 0;
$('.target').on('click', function() {
  if (touchtime == 0) {
    touchtime = new Date().getTime();
  } else {
    if (((new Date().getTime()) - touchtime) < 800) {
      alert("double clicked");
      touchtime = 0;
    } else {
      touchtime = 0;
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<p class="target">click me!</p>
<p class="target">then click me!</p>

<a href="#">click link</a>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
B.F.playz
  • 21
  • 2
2

Multiple targets with own doubleclick counter. The accepted solution has 2 bugs, that are fixed here:

  1. If you click on target and click outside and click on target again within 800 ms, then the doubleclick event fires.

  2. If you have multiple targets, click on different targets within 800 ms, and the doubleclick event fires.

$(document).on("click", function(e)
{
    var MAX_DELAY_IN_MS = 800;
    var current_time = new Date();
    var targets = $(".target");
    
    if ((typeof last_target == "undefined") || 
        (last_target == 0))
    {
        last_target = e.target;
        last_click  = current_time;
    }
    else
    {
        if ((last_target == e.target) && 
            ((targets.is(e.target) == true) || 
             (targets.has(e.target).length !== 0)) &&
            (current_time - last_click < MAX_DELAY_IN_MS))
        {
            alert("double clicked");
        }
        last_target = 0;
        last_click  = 0;
    }
});
div{display:inline-block; width:30px; height:30px; margin:5px;}
.target{background-color:lime;}
.no_target{background-color:orange;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<div class="target"></div>
<div class="target"></div>
<div class="no_target"></div>
<div class="target"></div>
Bogdán
  • 31
  • 4
  • please elaborate how your answer differs from the accepted answer and why do you consider worth to be posted? – fenixil Nov 10 '19 at 23:00
  • Thank you fenixil! I'm new here. The accepted solution has a bug. If you click "click me!" and then click on "then click me!" within 800 ms, the doubleclick event fires, however it wasn't a real doubleclick. In my solution the events are handled separately. – Bogdán Nov 12 '19 at 16:12
  • I was thinking about my solution, and found another bug. If you click on the first target, second target, frist target within 800 ms, then the doubleclick event fires (shouldn't). For my purposes it's enough. Perhaps none of the solutions are perfect... – Bogdán Nov 12 '19 at 16:14
  • Please consider to add these details to your answer - that explains the difference and might hep you to gain reputation faster – fenixil Nov 12 '19 at 18:22
  • Good idea, thank you fenixil! Btw reputation is not my goal. – Bogdán Nov 17 '19 at 22:39
2

Programmatically all of the answers given above are fine. When you double click on mouse button it's just the mass off your finger involved, so it can be fast...

On the other hand when tapping touch screen usually much larger physical mass is involved. Larger mass means slower times . So my approach is "click two times" instead of double click.

Means a global variable e.g var ClickCounter=0; Inside the function scope

 ClickCounter++;
 Check if  ClickCounter ==2.
 Execute your Code.
 Reset counter ClickCounter=0 
 else return false or execute another code
bguiz
  • 27,371
  • 47
  • 154
  • 243
0

I have an improvement to the code above, that didn´t detect a doubleclick after a single click:

var touchtime = 0;
$(".target").on("click", function() {
  if (((new Date().getTime()) - touchtime) < 500) {
    alert("double clicked");
  }
  touchtime = new Date().getTime();
});

This code detects all doubleclicks. I also reduced the touchtime to 500ms (standard doubleclick-time).

0

The only way is to detect double touch yourselves. You can do it by persisting last touch event timestamp like below:

if (e.touches.length === 1) {
  if (this.lastTouchEventTimeStamp) {
    const timeInMillisecondsSinceLastTouch = e.timeStamp - this.lastTouchEventTimeStamp;
    if (timeInMillisecondsSinceLastTouch > 80 && timeInMillisecondsSinceLastTouch < 400) {
      // double tap will be detected here
      this.lastTouchEventTimeStamp = undefined;

      const dblClickEvent = new DragEvent('dblclick', {
        view: window,
        bubbles: true,
        cancelable: true
      });

      e.target.dispatchEvent(dblClickEvent);
    }
  }

  this.lastTouchEventTimeStamp = e.timeStamp;
}
zmechanic
  • 1,842
  • 21
  • 27
0

Came across this thread and wanted to supply an updated answer.

function doubleClick(event, callback) {
  var touchtime = $(event.target).data("touch-time");
  if (touchtime == undefined || touchtime == 0) {
    // set first click
    $(event.target).data("touch-time", new Date().getTime());
  } else {
    // compare first click to this click and see if they occurred within double click threshold
    if (((new Date().getTime()) - touchtime) < 800) {
      // double click occurred
      callback();
      $(event.target).data("touch-time", 0);
    } else {
      // not a double click so set as a new first click
      $(event.target).data("touch-time", new Date().getTime());
    }
  }
}

It can then be used as follows:

$(selector).click(function(event){
  doubleClick(event, function(){
    console.log("Hello World");
  });
});

This uses the Data Attribute versus a global variable to get/set the Touch Time.

The standard dblclick should work in modern mobile browsers.

Twisty
  • 30,304
  • 2
  • 26
  • 45
-1

This is it... in CoffeeScript

onDblClick = -> "...your function to be fired..."
dbl_click = null
$(element).on 'mousedown', ->
   onDblClick() if dbl_click
   dbl_click = true
   setTimeout () ->
       dbl_click = false            
   , 250
eGroz
  • 1
-2

You need to enter "return false" to the end of the function like below

var touchtime = 0;
$('.dbclickopen').click(function() {
    if(touchtime == 0) {
        //set first click
        touchtime = new Date().getTime();
    } else {
        //compare first click to this click and see if they occurred within double click threshold
        if(((new Date().getTime())-touchtime) < 800) {
            //double click occurred
            touchtime = 0;
            window.location = this.href;
        } else {
            //not a double click so set as a new first click
            touchtime = new Date().getTime();
        }
    }
    return false;
});
Hemant Jadhav
  • 95
  • 1
  • 4
  • Even with return false, it does not work on mobile, at least not Android. For some reason, the default behavior (zoom/unzoom) is not prevented – matteo Oct 23 '15 at 17:12