[javascript] How to differentiate single click event and double click event?

I have a single button in li with id "my_id". I attached two jQuery events with this element

1.

$("#my_id").click(function() { 
    alert('single click');
});

2.

$("#my_id").dblclick(function() {
    alert('double click');
});

But every times it gives me the single click

This question is related to javascript jquery jquery-events

The answer is


A simple function. No jquery or other framework is required. Pass your functions as parameters

<div onclick="doubleclick(this, function(){alert('single')}, function(){alert('double')})">click me</div>
    <script>
        function doubleclick(el, onsingle, ondouble) {
            if (el.getAttribute("data-dblclick") == null) {
                el.setAttribute("data-dblclick", 1);
                setTimeout(function () {
                    if (el.getAttribute("data-dblclick") == 1) {
                        onsingle();
                    }
                    el.removeAttribute("data-dblclick");
                }, 300);
            } else {
                el.removeAttribute("data-dblclick");
                ondouble();
            }
        }
    </script>

Here's an alternative of jeum's code for an arbitrary number of events:

 var multiClickHandler = function (handlers, delay) {
    var clicks = 0, timeout, delay = delay || 250;
    return function (e) {
      clicks++;
      clearTimeout(timeout);
      timeout = setTimeout(function () {
        if(handlers[clicks]) handlers[clicks](e);
        clicks = 0;
      }, delay);
    };
  }

  cy.on('click', 'node', multiClickHandler({
    1: function(e){console.log('single clicked ', e.cyTarget.id())},
    2: function(e){console.log('double clicked ', e.cyTarget.id())},
    3: function(e){console.log('triple clicked ', e.cyTarget.id())},
    4: function(e){console.log('quadro clicked ', e.cyTarget.id())},
    // ...
  }, 300));

Needed this for a cytoscape.js app.


Instead of utilizing more ad-hoc states and setTimeout, turns out there is a native property called detail that you can access from the event object!

element.onclick = event => {
   if (event.detail === 1) {
     // it was a single click
   } else if (event.detail === 2) {
     // it was a double click
   }
};

Modern browsers and even IE-9 supports it :)

Source: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail


I know this is old, but below is a JS only example of a basic loop counter with a single timer to determine a single vs double click. Hopefully this helps someone.

var count = 0;
var ele = document.getElementById("my_id");
ele.addEventListener('click', handleSingleDoubleClick, false); 

function handleSingleDoubleClick()
{
  if(!count) setTimeout(TimerFcn, 400); // 400 ms click delay
  count += 1;
}
function TimerFcn() 
{
  if(count > 1) console.log('you double clicked!')
  else console.log('you single clicked')
  count = 0;
}

I wrote a simple jQuery plugin that lets you use a custom 'singleclick' event to differentiate a single-click from a double-click:

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

$('#someDiv').on('singleclick', function(e) {
    // The event will be fired with a small delay.
    console.log('This is certainly a single-click');
}

this worked for me–

var clicked=0;
function chkBtnClcked(evnt) {
    clicked++;
    // wait to see if dblclick
    if (clicked===1) {
        setTimeout(function() {
            clicked=0;
            .
            .
        }, 300); // test for another click within 300ms
    }
    if (clicked===2) {
        stopTimer=setInterval(function() {
            clicked=0;
            .
            .
        }, 30*1000); // refresh every 30 seconds
    }
}

usage–

<div id="cloneimages" style="position: fixed;" onclick="chkBtnClcked(evnt)"  title="Click for next pic; double-click for slide show"></div>

Another simple Vanilla solution based on the A1rPun answer (see his fiddle for the jQuery solution, and both are in this one).

It seems that to NOT trigger a single-click handler when the user double-clicks, the single-click handler is necessarily triggered after a delay...

var single = function(e){console.log('single')},
    double = function(e){console.log('double')};

var makeDoubleClick = function(e) {

  var clicks = 0,
      timeout;

  return function (e) {

    clicks++;

    if (clicks == 1) {
      timeout = setTimeout(function () {
        single(e);
        clicks = 0;
      }, 250);
    } else {
      clearTimeout(timeout);
      double(e);
      clicks = 0;
    }
  };
}
document.getElementById('btnVanilla').addEventListener('click', makeDoubleClick(), false);

Use the excellent jQuery Sparkle plugin. The plugin gives you the option to detect first and last click. You can use it to differentiate between click and dblclick by detecting if another click was followed by the first click.

Check it out at http://balupton.com/sandbox/jquery-sparkle/demo/


How to differentiate between single clicks and double clicks on one and the same element?

If you don't need to mix them, you can rely on click and dblclick and each will do the job just fine.

A problem arises when trying to mix them: a dblclick event will actually trigger a click event as well, so you need to determine whether a single click is a "stand-alone" single click, or part of a double click.

In addition: you shouldn't use both click and dblclick on one and the same element:

It is inadvisable to bind handlers to both the click and dblclick events for the same element. The sequence of events triggered varies from browser to browser, with some receiving two click events before the dblclick and others only one. Double-click sensitivity (maximum time between clicks that is detected as a double click) can vary by operating system and browser, and is often user-configurable.
Source: https://api.jquery.com/dblclick/

Now on to the good news:

You can use the event's detail property to detect the number of clicks related to the event. This makes double clicks inside of click fairly easy to detect.

The problem remains of detecting single clicks and whether or not they're part of a double click. For that, we're back to using a timer and setTimeout.

Wrapping it all together, with use of a data attribute (to avoid a global variable) and without the need to count clicks ourselves, we get:

HTML:

<div class="clickit" style="font-size: 200%; margin: 2em; padding: 0.25em; background: orange;">Double click me</div>

<div id="log" style="background: #efefef;"></div>

JavaScript:

<script>
var clickTimeoutID;
$( document ).ready(function() {

    $( '.clickit' ).click( function( event ) {

        if ( event.originalEvent.detail === 1 ) {
            $( '#log' ).append( '(Event:) Single click event received.<br>' );

            /** Is this a true single click or it it a single click that's part of a double click?
             * The only way to find out is to wait it for either a specific amount of time or the `dblclick` event.
             **/
            clickTimeoutID = window.setTimeout(
                    function() {
                        $( '#log' ).append( 'USER BEHAVIOR: Single click detected.<br><br>' );
                    },
                    500 // how much time users have to perform the second click in a double click -- see accessibility note below.
                );

        } else if ( event.originalEvent.detail === 2 ) {
            $( '#log' ).append( '(Event:) Double click event received.<br>' );
            $( '#log' ).append( 'USER BEHAVIOR: Double click detected.<br>' );
            window.clearTimeout( clickTimeoutID ); // it's a dblclick, so cancel the single click behavior.
        } // triple, quadruple, etc. clicks are ignored.

    });

});
</script>

Demo:

JSfiddle


Notes about accessibility and double click speeds:

  • As Wikipedia puts it "The maximum delay required for two consecutive clicks to be interpreted as a double-click is not standardized."
  • No way of detecting the system's double-click speed in the browser.
  • Seems the default is 500 ms and the range 100-900mms on Windows (source)
  • Think of people with disabilities who set, in their OS settings, the double click speed to its slowest.
    • If the system double click speed is slower than our default 500 ms above, both the single- and double-click behaviors will be triggered.
    • Either don't use rely on combined single and double click on one and the same item.
    • Or: add a setting in the options to have the ability to increase the value.

It took a while to find a satisfying solution, I hope this helps!


This answer is made obsolete through time, check @kyw's solution.

I created a solution inspired by the gist posted by @AdrienSchuler. Use this solution only when you want to bind a single click AND a double click to an element. Otherwise I recommend using the native click and dblclick listeners.

These are the differences:

  • Vanillajs, No dependencies
  • Don't wait on the setTimeout to handle the click or doubleclick handler
  • When double clicking it first fires the click handler, then the doubleclick handler

Javascript:

function makeDoubleClick(doubleClickCallback, singleClickCallback) {
    var clicks = 0, timeout;
    return function() {
        clicks++;
        if (clicks == 1) {
            singleClickCallback && singleClickCallback.apply(this, arguments);
            timeout = setTimeout(function() { clicks = 0; }, 400);
        } else {
            timeout && clearTimeout(timeout);
            doubleClickCallback && doubleClickCallback.apply(this, arguments);
            clicks = 0;
        }
    };
}

Usage:

var singleClick = function(){ console.log('single click') };
var doubleClick = function(){ console.log('double click') };
element.addEventListener('click', makeDoubleClick(doubleClick, singleClick));

Below is the usage in a jsfiddle, the jQuery button is the behavior of the accepted answer.

jsfiddle


I'm afraid that the behaviour is browser dependent:

It is inadvisable to bind handlers to both the click and dblclick events for the same element. The sequence of events triggered varies from browser to browser, with some receiving two click events before the dblclick and others only one. Double-click sensitivity (maximum time between clicks that is detected as a double click) can vary by operating system and browser, and is often user-configurable.

http://api.jquery.com/dblclick/

Running your code in Firefox, the alert() in the click() handler prevents you from clicking a second time. If you remove such alert, you get both events.


Just posting the native HTML answer just in case the need is to be easy and HTML.

<p ondblclick="myFunction()" id = 'id'>Double-click me</p>

This of course has native Jquery options. ie... $('#id').attr('ondblclick',function(){...}) or, as stated previously, $('#id').dblclick(function(){...});


let clickTimes = 0;
let timer = null;
roundBox.click = function (e) {
  clearTimeout(timer);
  timer = setTimeout(() => { // ????
    console.log("single click");
  }, 600);
  clickTimes++;

  if (clickTimes == 2) { // ??
    clearTimeout(timer);
    clickTimes = 0;
    console.log("double click");
    toggleExpanded(id);
  }
}

Well in order to double click (click twice) you must first click once. The click() handler fires on your first click, and since the alert pops up, you don't have a chance to make the second click to fire the dblclick() handler.

Change your handlers to do something other than an alert() and you'll see the behaviour. (perhaps change the background color of the element):

$("#my_id").click(function() { 
    $(this).css('backgroundColor', 'red')
});

$("#my_id").dblclick(function() {
    $(this).css('backgroundColor', 'green')
});

The behavior of the dblclick event is explained at Quirksmode.

The order of events for a dblclick is:

  1. mousedown
  2. mouseup
  3. click
  4. mousedown
  5. mouseup
  6. click
  7. dblclick

The one exception to this rule is (of course) Internet Explorer with their custom order of:

  1. mousedown
  2. mouseup
  3. click
  4. mouseup
  5. dblclick

As you can see, listening to both events together on the same element will result in extra calls to your click handler.


Based on Adrien Schuler (thank you so much!!!) answer, for Datatables.net and for many uses, here is a modification:

Function

/**
 * For handle click and single click in child's objects
 * @param {any} selector Parents selector, like 'tr'
 * @param {any} single_click_callback Callback for single click
 * @param {any} double_click_callback Callback for dblclick
 * @param {any} timeout Timeout, optional, 300 by default
 */
jQuery.fn.single_double_click = function (selector, single_click_callback, double_click_callback, timeout) {
    return this.each(function () {
        let clicks = 0;
        jQuery(this).on('click', selector, function (event) {
            let self = this;
            clicks++;
            if (clicks == 1) {
                setTimeout(function () {
                    if (clicks == 1) {
                        single_click_callback.call(self, event);
                    } else {
                        double_click_callback.call(self, event);
                    }
                    clicks = 0;
                }, timeout || 300);
            }
        });
    });
}

Use

$("#MyTableId").single_double_click('tr',
            function () {   //  Click
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("Click in "+id+" "+data);
            },
            function () {   //  DBLClick
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("DBLClick in "+id+" "+data);
            }
        );

The modern correct answer is a mix between the accepted answer and @kyw 's solution. You need a timeout to prevent that first single click and the event.detail check to prevent the second click.

_x000D_
_x000D_
const button = document.getElementById('button')_x000D_
let timer_x000D_
button.addEventListener('click', event => {_x000D_
  if (event.detail === 1) {_x000D_
    timer = setTimeout(() => {_x000D_
      console.log('click')_x000D_
    }, 200)_x000D_
  }_x000D_
})_x000D_
button.addEventListener('dblclick', event => {_x000D_
  clearTimeout(timer)_x000D_
  console.log('dblclick')_x000D_
})
_x000D_
<button id="button">Click me</button>
_x000D_
_x000D_
_x000D_


I like to avoid jquery (and other 90-140k libs), and as noted browsers handle onclick first, so here is what I did on a website I created (this example also covers getting a clicked location local x y )

clicksNow-0; //global js, owell

function notify2(e, right) {  // called from onclick= and oncontextmenu= (rc)
var x,y,xx,yy;
var ele = document.getElementById('wrap');  
    // offset fixed parent for local win x y
var xxx= ele.offsetLeft;
var yyy= ele.offsetTop;

//NScape
if (document.layers || document.getElementById&&!document.all) {
    xx= e.pageX;
    yy= e.pageY;
} else {
    xx= e.clientX;
    yy= e.clientY;
}
x=xx-xxx;
y=yy-yyy;

clicksNow++;
    // 200 (2/10ths a sec) is about a low as i seem to be able to go
setTimeout( "processClick( " + right + " , " + x + " , " + y + ")", 200);
}

function processClick(right, x, y) {
if (clicksNow==0) return; // already processed as dblclick
if (clicksNow==2) alert('dbl');
clicksNow=0;
    ... handle, etc ...
}

hope that helps


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to jquery-events

Failed to load resource: the server responded with a status of 500 (Internal Server Error) in Bind function Detect Close windows event by jQuery How to bind Events on Ajax loaded Content? Get clicked element using jQuery on event? jQuery click events firing multiple times jQuery.click() vs onClick Bootstrap onClick button event Difference between $(this) and event.target? Getting the class of the element that fired an event using JQuery Attaching click event to a JQuery object not yet added to the DOM