Javascript with jQuery: Click and double click on same element, different effect, one disables the other

The general idea:

  1. Upon the first click, dont call the associated function (say single_click_function()). Rather, set a timer for a certain period of time(say x). If we do not get another click during that time span, go for the single_click_function(). If we do get one, call double_click_function()

  2. Timer will be cleared once the second click is received. It will also be cleared once x milliseconds are lapsed.

BTW, check Paolo's reply out: Need to cancel click/mouseup events when double-click event detected and of course the entire thread! :-)

Better answer: https://stackoverflow.com/a/7845282/260610


Working demo

$('#alreadyclicked').val('no click');
$('td.dblclickable').on('click',function(){
    var $button=$(this);
    if ($button.data('alreadyclicked')){
        $button.data('alreadyclicked', false); // reset
        $('#alreadyclicked').val('no click');

        if ($button.data('alreadyclickedTimeout')){
            clearTimeout($button.data('alreadyclickedTimeout')); // prevent this from happening
        }
        // do what needs to happen on double click. 
        $('#action').val('Was double clicked');
    }else{
        $button.data('alreadyclicked', true);
        $('#alreadyclicked').val('clicked');
        var alreadyclickedTimeout=setTimeout(function(){
            $button.data('alreadyclicked', false); // reset when it happens
            $('#alreadyclicked').val('no click');
            $('#action').val('Was single clicked');
            // do what needs to happen on single click. 
            // use $button instead of $(this) because $(this) is 
            // no longer the element
        },300); // <-- dblclick tolerance here
        $button.data('alreadyclickedTimeout', alreadyclickedTimeout); // store this id to clear if necessary
    }
    return false;
});

obviously use <td class="dblclickable">


I wrote a simple jQuery plugin that lets you use a custom 'singleclick' event to differentiate a single-click from a double-click. This allows you to build an interface where a single-click makes the input editable while a double-click expands it. Much like Windows/OSX filesystem rename/open UI.

https://github.com/omriyariv/jquery-singleclick

$('#someInput').on('singleclick', function(e) {
    // The event will be fired with a small delay but will not fire upon a double-click.
    makeEditable(e.target);
}

$('#container').on('dblclick', function(e) {
    // Expand the row...
}

Rewrite user822711's answer for reuse:

  $.singleDoubleClick = function(singleClk, doubleClk) {
    return (function() {
      var alreadyclicked = false;
      var alreadyclickedTimeout;

      return function(e) {
        if (alreadyclicked) {
          // double
          alreadyclicked = false;
          alreadyclickedTimeout && clearTimeout(alreadyclickedTimeout);
          doubleClk && doubleClk(e);
        } else {
          // single
          alreadyclicked = true;
          alreadyclickedTimeout = setTimeout(function() {
            alreadyclicked = false;
            singleClk && singleClk(e);
          }, 300);
        }
      }
    })();
  }

Call the function.

$('td.dblclickable').bind('click', $.singleDoubleClick(function(e){
  //single click.
}, function(e){
  //double click.
}));

The issue only occurs when the editable field is clicked, so attach a regular click handler to that element which will cancel propagation of the event (see stopPropagation) and will set a timeout (setTimeout(...)) for, say, 600ms (default time between two clicks to be deemed a dbl-click is 500ms [src]). If, by that time the dblclick has not occurred (you can have a var accessible in both event handlers that acts as a flag to detect this) then you can assume the user wants to expand the row instead and continue with that action...

IMO, you should re-think this. Alas, a single click handler cannot know if the user is about to double-click.

I suggest making both actions single click, and simply don't propagate up from the editable field when it is clicked.