Javascript : Click and Double Click on Same Element
As we begin to emulate desktop applications more and more with our web apps, one thing you may come across the need for is a way to get both click and double click to work on the same element without screwing each other up. I spent part of Friday trying to get this exact functionality to work correctly, so I thought I would make a quick post on what I did.
I’ll be using a table row as the target of clicks, and jQuery throughout because that is what I use.
So, simple table structure with nothing special except an id on the table for a hook.
<table id="myTable"> <thead><tr><th>Row Header</th></tr></thead> <tbody> <tr><td>Click Me!!!</td></tr> <tr><td>Click Me!!!</td></tr> </tbody> </table>
See? Nothing special. For whatever reason, we need one action to happen when a user clicks one of those rows, and a different action to happen when the user double clicks. To do that, we will use the dreaded ‘setTimeout()’. You hate it, I know. We are going to use it anyway.
First up, we need two variables.
/* Variables */
01. var clickTimeout = null,
02. clickDelay = 100; //milliseconds
These, of course, are inside of the closure all your code is in, right? No screwing with the global namespace for us.
Now, I’m just going to throw all the rest of code at you at once and break some bits down after. Here it is.
03. $('#myTable tbody tr').live('click', function(){
04. if(clickTimeout){ return; }
05.
06. clickTimeout = window.setTimeout(function(){
07. //do whatever you want to do right here
08. clickTimeout = null;
09. }, clickDelay);
10. })
11. .live('dblclick',function(){
12. if(clickTimeout){
13. clearTimeout(clickTimeout);
14. clickTimeout = null;
15. }
16. //do whatever you want to do right here
17. });
Lines 3 and 11 just add the click and double click lines, respectively, with jQuery goodness. Line 6 sets up a time out whenever the user clicks a row, with a delay of 100 milliseconds (see lines 9 and 2). So after 100ms, this timeout will fire and do whatever you wanted to do on click. If they only click once, then all is well and this works just fine.
But we need a double click in there and don’t want the click action to fire if the user double clicks. So see line 12. If ‘clickTimeout’ exists (and it will since a click always precedes a double click), then remove it with clearTimeout, thus stopping the click event from ever happening. Then just do whatever you want to do with the double click (line 16).
That is it except for one thing, line 4. Because setTimeout() returns a unique id every time it is called, each click in a double click will get it’s own timeout event. So without that line, the second click would call setTimeout() again, and that id would replace the one our ‘clickTimeout’ variable is storing. But the actual timeout itself is not replaced, just the variable that holds the id! This means that the action from the first click fires even though the double click function clears the timeout from the second click. To prevent this, we simply check to see if clickTimeout is set (meaning they clicked less than 100ms ago and are going to trigger the double click), and if so, return.
I was working in FF, so IE’s odd handling of the order of click events may require extra tuning or checks in the script. But that’s another day.
