Related
I want avoid that double click also fire a single click event.
A simple solution i found is to delay the click with a timer and destroy the timer if a double click is fired.
var pendingClick;
function myclick(){
clearTimeout(pendingClick);
pendingClick = setTimeout(function(){
console.log('click');
}, 500);
}
function mydblclick(){
clearTimeout(pendingClick);
console.log('double click');
}
<div onclick="myclick()" ondblclick="mydblclick()">Double Click Me!</div>
But this solution is based on timing, if the double click is too slow (>500ms) it also fire a single click.
There is a stable solution for handle both click and double click?
Double-clicking in itself is "based on timing", even in the standard implementation of dblclick / ondblclick. There will always be the issue of a single-click being fired if the double-click is "too slow". What is "too slow"? 300ms? 500ms? 1000ms? Your double-clicks may be only 50ms apart, while my mom's double-clicks are 1-2 seconds apart...
You can get the event and cancel it with the addEventListener like this:
document.addEventListener('dblclick', (event) => {
event.preventDefault();
event.stopPropagation();
}, true); // With this true, you are cancelling the dblclick event
let pendingClick;
function myclick(){
clearTimeout(pendingClick);
pendingClick = setTimeout(function (){
console.log('click');
}, 500);
}
function mydblclick(){
clearTimeout(pendingClick);
console.log('double click');
}
<div onclick="myclick()" ondblclick="mydblclick()">Double Click Me!</div>
Only work with the 'onclick' function to check if it was one or two clicks and use a variable to count the number of clicks in a given time interval.
Example:
var pendingClick;
var clicked = 0;
var time_dbclick = 500 // 500ms
function myclick(){
clicked++;
if(clicked >= 2){
mydblclick()
clearTimeout(pendingClick)
clicked = 0;
return;
}
clearTimeout(pendingClick)
pendingClick = setTimeout(() => {
console.log('One click!')
clicked = 0;
}, time_dbclick);
}
function mydblclick(){
console.log('double click');
}
<div onclick="myclick()">Double Click Me!</div>
Custom Events instead of inline event handlers
If one prefers to use .addEventListener and .removeEventListener instead of HTML inline-eventhandlers, I would suggest another approach based on Custom Events. That means one would not make use of the standard implementation of "click" and "dblclick", but create own event handling for both:
let lastLeftClick = document.dispatchEvent(new Event("click"));
let doubleclickLength = 300;
function leftClickHandler (e) {
if (e.button != 0) return; // only left clicks shall be handled;
let delaySinceLastClick = e.timeStamp - lastLeftClick.timeStamp;
let eIsDoubleClick = delaySinceLastClick < doubleclickLength;
if (eIsDoubleClick) {
let doubleclickEvt = new CustomEvent("doubleclick", e);
lastLeftClick = lastLeftClick = doubleclickEvt;
document.dispatchEvent(doubleclickEvt);
} else {
let singleClickEvt = new CustomEvent("singleclick", e);
lastLeftClick = singleClickEvt;
document.dispatchEvent(lastLeftClick);
}
}
// adding above click event implementation:
document.addEventListener("click", leftClickHandler);
using the new custom events:
document.addEventListener("singleclick", e=>console.log("single click"));
document.addEventListener("doubleclick", e=>console.log("double click"));
Adding Event Listener
function Solitaire() {
this.table.addEventListener("click", this.handleClick.bind(this));
this.table.addEventListener("dblclick", this.handleDoubleClick.bind(this));
}
Handling Event
Solitaire.prototype.handleDoubleClick = function(event) {
console.log("DoubleClick");
};
Solitaire.prototype.handleClick = function(event) {
console.log("Click");
};
Expected output (in console) on a double click event
DoubleClick
But the output I get in console:
Click
Click
DoubleClick
I don't know about easeljs, but I can tell you about how it is done in jQuery, where you need to "hack" it to make it actually work.
var DELAY = 500;
$('#my_element').on('click', function(e){
++clicks; // Count the clicks
if(clicks === 1){
// One click has been made
var myTimerToDetectDoubleClick = setTimeout(function(){
console.log('This was a single click');
doStuffForSingleClick();
clicks = 0;
}, DELAY);
} // End of if
else{
// Someone is clicking pretty damn fast, they probably mean double click :p
clearTimeout(myTimerToDetectDoubleClick);
doStuffForDoubleClick();
clicks = 0;
}
}).on('dblclick', function(evt){
evt.preventDefault(); // cancel system's default double click
});
The basic essence will remain the same for event handling for easeljs. You can imitate this behaviour accordingly there.
Is there something in jquery that would allow me to differentiate between behavior on double click and single click?
When I bind both to same element only the single click gets executed.
Is there a way that wait for some time before execution of the single click to see if the user clicks again or not?
Thanks :)
I found that John Strickler's answer did not quite do what I was expecting. Once the alert is triggered by a second click within the two-second window, every subsequent click triggers another alert until you wait two seconds before clicking again. So with John's code, a triple click acts as two double clicks where I would expect it to act like a double click followed by a single click.
I have reworked his solution to function in this way and to flow in a way my mind can better comprehend. I dropped the delay down from 2000 to 700 to better simulate what I would feel to be a normal sensitivity. Here's the fiddle: http://jsfiddle.net/KpCwN/4/.
Thanks for the foundation, John. I hope this alternate version is useful to others.
var DELAY = 700, clicks = 0, timer = null;
$(function(){
$("a").on("click", function(e){
clicks++; //count clicks
if(clicks === 1) {
timer = setTimeout(function() {
alert("Single Click"); //perform single-click action
clicks = 0; //after action performed, reset counter
}, DELAY);
} else {
clearTimeout(timer); //prevent single-click action
alert("Double Click"); //perform double-click action
clicks = 0; //after action performed, reset counter
}
})
.on("dblclick", function(e){
e.preventDefault(); //cancel system double-click event
});
});
The solution given from "Nott Responding" seems to fire both events, click and dblclick when doubleclicked. However I think it points in the right direction.
I did a small change, this is the result :
$("#clickMe").click(function (e) {
var $this = $(this);
if ($this.hasClass('clicked')){
$this.removeClass('clicked');
alert("Double click");
//here is your code for double click
}else{
$this.addClass('clicked');
setTimeout(function() {
if ($this.hasClass('clicked')){
$this.removeClass('clicked');
alert("Just one click!");
//your code for single click
}
}, 500);
}
});
Try it
http://jsfiddle.net/calterras/xmmo3esg/
Sure, bind two handlers, one to click and the other to dblclick. Create a variable that increments on every click. then resets after a set delay. Inside the setTimeout function you can do something...
var DELAY = 2000,
clicks = 0,
timer = null;
$('a').bind({
click: function(e) {
clearTimeout(timer);
timer = setTimeout(function() {
clicks = 0;
}, DELAY);
if(clicks === 1) {
alert(clicks);
//do something here
clicks = 0;
}
//Increment clicks
clicks++;
},
dblclick: function(e) {
e.preventDefault(); //don't do anything
}
});
You could probably write your own custom implementation of click/dblclick to have it wait for an extra click. I don't see anything in the core jQuery functions that would help you achieve this.
Quote from .dblclick() at the jQuery site
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.
Look at the following code
$("#clickMe").click(function (e) {
var $this = $(this);
if ($this.hasClass('clicked')){
alert("Double click");
//here is your code for double click
return;
}else{
$this.addClass('clicked');
//your code for single click
setTimeout(function() {
$this.removeClass('clicked'); },500);
}//end of else
});
Demo goes here http://jsfiddle.net/cB484/
I've written a jQuery plugin that allow also to delegate the click and dblclick events
// jQuery plugin to bind both single and double click to objects
// parameter 'delegateSelector' is optional and allow to delegate the events
// parameter 'dblclickWait' is optional default is 300
(function($) {
$.fn.multipleClicks = function(delegateSelector, clickFun, dblclickFun, dblclickWait) {
var obj;
if (typeof(delegateSelector)==='function' && typeof(clickFun)==='function') {
dblclickWait = dblclickFun; dblclickFun = clickFun; clickFun = delegateSelector; delegateSelector = null; // If 'delegateSelector' is missing reorder arguments
} else if (!(typeof(delegateSelector)==='string' && typeof(clickFun)==='function' && typeof(dblclickFun)==='function')) {
return false;
}
return $(this).each(function() {
$(this).on('click', delegateSelector, function(event) {
var self = this;
clicks = ($(self).data('clicks') || 0)+1;
$(self).data('clicks', clicks);
if (clicks == 1) {
setTimeout(function(){
if ($(self).data('clicks') == 1) {
clickFun.call(self, event); // Single click action
} else {
dblclickFun.call(self, event); // Double click action
}
$(self).data('clicks', 0);
}, dblclickWait || 300);
}
});
});
};
})(jQuery);
This solution works for me
var DELAY = 250, clicks = 0, timer = null;
$(".fc-event").click(function(e) {
if (timer == null) {
timer = setTimeout(function() {
clicks = 0;
timer = null;
// single click code
}, DELAY);
}
if(clicks === 1) {
clearTimeout(timer);
timer = null;
clicks = -1;
// double click code
}
clicks++;
});
i am implementing this simple solution , http://jsfiddle.net/533135/VHkLR/5/
html code
<p>Click on this paragraph.</p>
<b> </b>
script code
var dbclick=false;
$("p").click(function(){
setTimeout(function(){
if(dbclick ==false){
$("b").html("clicked")
}
},200)
}).dblclick(function(){
dbclick = true
$("b").html("dbclicked")
setTimeout(function(){
dbclick = false
},300)
});
its not much laggy
var singleClickTimer = 0; //define a var to hold timer event in parent scope
jqueryElem.click(function(e){ //using jquery click handler
if (e.detail == 1) { //ensure this is the first click
singleClickTimer = setTimeout(function(){ //create a timer
alert('single'); //run your single click code
},250); //250 or 1/4th second is about right
}
});
jqueryElem.dblclick(function(e){ //using jquery dblclick handler
clearTimeout(singleClickTimer); //cancel the single click
alert('double'); //run your double click code
});
I made some changes to the above answers here which still works great: http://jsfiddle.net/arondraper/R8cDR/
Below is my simple approach to the issue.
JQuery function:
jQuery.fn.trackClicks = function () {
if ($(this).attr("data-clicks") === undefined) $(this).attr("data-clicks", 0);
var timer;
$(this).click(function () {
$(this).attr("data-clicks", parseInt($(this).attr("data-clicks")) + 1);
if (timer) clearTimeout(timer);
var item = $(this);
timer = setTimeout(function() {
item.attr("data-clicks", 0);
}, 1000);
});
}
Implementation:
$(function () {
$("a").trackClicks();
$("a").click(function () {
if ($(this).attr("data-clicks") === "2") {
// Double clicked
}
});
});
Inspect the clicked element in Firefox/Chrome to see data-clicks go up and down as you click, adjust time (1000) to suit.
(function($){
$.click2 = function (elm, o){
this.ao = o;
var DELAY = 700, clicks = 0;
var timer = null;
var self = this;
$(elm).on('click', function(e){
clicks++;
if(clicks === 1){
timer = setTimeout(function(){
self.ao.click(e);
}, DELAY);
} else {
clearTimeout(timer);
self.ao.dblclick(e);
}
}).on('dblclick', function(e){
e.preventDefault();
});
};
$.click2.defaults = { click: function(e){}, dblclick: function(e){} };
$.fn.click2 = function(o){
o = $.extend({},$.click2.defaults, o);
this.each(function(){ new $.click2(this, o); });
return this;
};
})(jQuery);
And finally we use as.
$("a").click2({
click : function(e){
var cid = $(this).data('cid');
console.log("Click : "+cid);
},
dblclick : function(e){
var cid = $(this).data('cid');
console.log("Double Click : "+cid);
}
});
Same as the above answer but allows for triple click. (Delay 500)
http://jsfiddle.net/luenwarneke/rV78Y/1/
var DELAY = 500,
clicks = 0,
timer = null;
$(document).ready(function() {
$("a")
.on("click", function(e){
clicks++; //count clicks
timer = setTimeout(function() {
if(clicks === 1) {
alert('Single Click'); //perform single-click action
} else if(clicks === 2) {
alert('Double Click'); //perform single-click action
} else if(clicks >= 3) {
alert('Triple Click'); //perform Triple-click action
}
clearTimeout(timer);
clicks = 0; //after action performed, reset counter
}, DELAY);
})
.on("dblclick", function(e){
e.preventDefault(); //cancel system double-click event
});
});
This is a method you can do using the basic JavaScript, which is works for me:
var v_Result;
function OneClick() {
v_Result = false;
window.setTimeout(OneClick_Nei, 500)
function OneClick_Nei() {
if (v_Result != false) return;
alert("single click");
}
}
function TwoClick() {
v_Result = true;
alert("double click");
}
If you don't want to create separate variables to manage the state, you can check this answer https://stackoverflow.com/a/65620562/4437468
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
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
The behavior of the dblclick event is explained at Quirksmode.
The order of events for a dblclick is:
mousedown
mouseup
click
mousedown
mouseup
click
dblclick
The one exception to this rule is (of course) Internet Explorer with their custom order of:
mousedown
mouseup
click
mouseup
dblclick
As you can see, listening to both events together on the same element will result in extra calls to your click handler.
You need to use a timeout to check if there is an another click after the first click.
Here is the trick:
// Author: Jacek Becela
// Source: http://gist.github.com/399624
// License: MIT
jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
return this.each(function(){
var clicks = 0, self = this;
jQuery(this).click(function(event){
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);
}
});
});
}
Usage:
$("button").single_double_click(function () {
alert("Try double-clicking me!")
}, function () {
alert("Double click detected, I'm hiding")
$(this).hide()
})
<button>Click Me!</button>
EDIT:
As stated below, prefer using the native dblclick event: http://www.quirksmode.org/dom/events/click.html
Or the one provided by jQuery: http://api.jquery.com/dblclick/
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.
const button = document.getElementById('button')
let timer
button.addEventListener('click', event => {
if (event.detail === 1) {
timer = setTimeout(() => {
console.log('click')
}, 200)
}
})
button.addEventListener('dblclick', event => {
clearTimeout(timer)
console.log('dblclick')
})
<button id="button">Click me</button>
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>
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.
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')
});
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
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);
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!
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.
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/
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');
}
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
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);
}
);
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);
}
}
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>
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(){...});
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;
}
Try this code
let click = 0;
element.onclick = (event) => {
click++;
console.log(click);
setTimeout(() => {
click = 0;
}, 300);
if (click === 2) {
console.log("double Click");
click = 0;
console.log(click);
}
};
If you want to distinguish between a single and double click, the event handler of the single click has to wait until it is proven, that the single click is not the beginning of a double click. This makes single clicks lagging. The example shows this.
var distinguish = (() => {
var target = null;
var timeout = null;
return (element, action) => {
element.addEventListener ('click', e => {
if (e.target === target) {
clearTimeout (timeout);
target = null;
timeout = null;
action ('double');
} else {
target = e.target;
timeout = setTimeout (() => {
target = null;
timeout = null;
action ('single');
}, 500);
}
});
};
})();
var button = document.getElementById ('button');
distinguish (button, kind => console.log (kind + ' click'));
<input id="button" type="button" value="click">
Pure JS, to truly differentiate single- vs double-click, (e.g. not triggering both at the same time). I'm using this combination of the native event.detail and a custom delay, to prevent the single-click from firing, if it gets cancelled by a double-click.
This approach is also very performance friendly, as it doesn't start a new timer every time we click in quick succession.
The only minor thing (as with some of the other solutions too), is that it may still fire both events, if the user double-clicks very very slowly. This can be prevented by highering the delay, but that would make single-clicking feel even more laggy.
Also there is a lot of differences in the suggested answers as to how they handle quick multi-clicking. So to make things clear, here is what happens in every consecutive click with this approach:
triggers a slightly delayed single-click, if it isn't cancelled by a doubleclick
triggers double-click
nothing
triggers double-click
nothing
...(every 2nd click is a doubleclick, which feels very natural)
I included a snippet so you can test it for yourself.
document.querySelector('button').addEventListener('click', single_or_double);
let isSingleClick; // flag to allow or cancel single clicks
function single_or_double(){
if (isSingleClick = event.detail == 1){ //check for a singleclick and store flag globally at the same time
setTimeout(() => {
if(isSingleClick){ //check if the flag is still set after the delay
console.log("single");
}
}, 200); // singleclick delay in milliseconds
}
else if (event.detail == 2) {
console.log("double");
}
}
<button>Single OR Double-Click</button>
I'm handling both the click and dblclick event on a DOM element. Each one carries out a different command, but I find that when double clicking on the element, in addition to firing the double click event, the click event is also fired twice. What is the best approach for preventing this behavior?
In case anyone else stumbles on this (as I did) looking for an answer, the absolute best solution that I could come up with is the following:
$node.on('click',function(e){
if(e.originalEvent.detail > 1){
return;
/* if you are returning a value from this
function then return false or cancel
the event some other way */
}
});
Done. If there is more than one click back to back, the second, third,etc. will not fire. I definitely prefer this to using any sort of timers.
I got myself pointed in this direction by reading this.
Incidentally: I was first researching this problem because I accidentally double clicked a paginated link, and the event fired and finished twice before the callback could happen.
Before coming up with the code above, I had
if e.originalEvent.detail === 2 //return
however, I was able to click on the link 3 times (a triple click), and though the second click didn't fire, the third did
In a comment, you said,
I delay the click handler by 300 ms (a noticeable and annoying delay) and even ...
So it sounds like what you want is that when you click then the DOM should geneate a click event immediately, except not if the click is the first click of a double-click.
To implement this feature, when you click, the DOM would need to be able to predict whether this is the final click or whether it's the first of a double-click (however I don't think is possible in general for the DOM to predict whether the user is about to click again).
What are the two distinct actions which you're trying to take on click and double-click? IMO, in a normal application you might want both events: e.g. single-click to focus on an element and then double-click to activate it.
When you must separate the events, some applications use something other than double-click: for example, they use right-click, or control-click.
You can use UIEvent.detail if you want to detect how many times the element was clicked and fire events based on that.
A simple example:
element.addEventListener("click", function (e) {
if (e.detail === 1) {
// do something if the element was clicked once.
} else if (e.detail === 2) {
// do something else if the element was clicked twice
}
});
In this case, it is best to delay the execution of the single click event slightly. Have your double click handler set a variable that the single click event will check. If that variable has a particular value, could be boolDoubleClick == true, then don't fire/handle the single click.
Thanks to all the other answers here as the combination of them seems to provide a reasonable solution for me when the interaction requires both, but mutually exclusive:
var pendingClick = 0;
function xorClick(e) {
// kill any pending single clicks
if (pendingClick) {
clearTimeout(pendingClick);
pendingClick = 0;
}
switch (e.detail) {
case 1:
pendingClick = setTimeout(function() {
console.log('single click action here');
}, 500);// should match OS multi-click speed
break;
case 2:
console.log('double click action here');
break;
default:
console.log('higher multi-click actions can be added as needed');
break;
}
}
myElem.addEventListener('click', xorClick, false);
Update: I added a generalized version of this approach along with a click polyfill for touch devices to this Github repo with examples:
https://github.com/mckamey/doubleTap.js
AFAIK DOM Level 2 Events makes no specification for double-click.
It doesn't work for me on IE7 (there's a shock), but FF and Opera have no problem managing the spec, where I can attach all actions to the click event, but for double-click just wait till the "detail" attribute of the event object is 2. From the docs: "If multiple clicks occur at the same screen location, the sequence repeats with the detail attribute incrementing with each repetition."
Here is what I did to distinguish within a module
node.on('click', function(e) {
//Prepare for double click, continue to clickHandler doesn't come soon enough
console.log("cleared timeout in click",_this.clickTimeout);
clearTimeout(_this.clickTimeout);
_this.clickTimeout = setTimeout(function(){
console.log("handling click");
_this.onClick(e);
},200);
console.log(_this.clickTimeout);
});
node.on('dblclick', function (e) {
console.log("cleared timeout in dblclick",_this.clickTimeout);
clearTimeout(_this.clickTimeout);
// Rest of the handler function
I use this solution for my project to prevent click event action, if I had dblclick event that should do different thing.
Note: this solution is just for click and dblclick and not any other thing like tripleclick or etc.
To see proper time between click and double click see this
sorry for my bad English.
I hope it helps :)
var button, isDblclick, timeoutTiming;
var clickTimeout, dblclickTimeout;
//-----
button = $('#button');
isDblclick = false;
/*
the proper time between click and dblclick is not standardized,
and is cutsomizable by user apparently (but this is windows standard I guess!)
*/
timeoutTiming = 500;
//-----
button.on('dblclick', function () {
isDblclick = true;
clearTimeout(dblclickTimeout);
dblclickTimeout = setTimeout(function () {
isDblclick = false;
}, timeoutTiming);
//-----
// here goes your dblclick codes
console.log('double clicked! not click.');
}).on('click', function () {
clearTimeout(clickTimeout);
clickTimeout = setTimeout(function () {
if(!isDblclick) {
// here goes your click codes
console.log('a simple click.');
}
}, timeoutTiming);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="button">
click/dblclick on this to see the result
</button>
It can be achieved via following code
var clickHandler = function(e) { /* put click event handling code here */ };
var doubleclickHandler = function(e) { /* put doubleclick event handling code here */ }
const maxMsBetweenClicks = 300;
var clickTimeoutId = null;
document.addEventListener("dblclick", handleDoubleClick);
document.addEventListener("click", handleSingleClick);
function handleSingleClick(e){
clearTimeout(clickTimeoutId);
clickTimeoutId = setTimeout( function() { clickHandler(e);}, maxMsBetweenClicks);
}
function handleDoubleClick(e){
clearTimeout(clickTimeoutId);
doubleclickHandler(e);
}
I know this is old as heck, but thought I'd post anyhow since I just ran into the same problem. Here's how I resolved it.
$('#alerts-display, #object-display').on('click', ['.item-data-summary', '.item-marker'], function(e) {
e.preventDefault();
var id;
id = setTimeout(() => {
// code to run here
return false;
}, 150);
timeoutIDForDoubleClick.push(id);
});
$('.panel-items-set-marker-view').on('dblclick', ['.summary', '.marker'], function(e) {
for (let i = 0; i < timeoutIDForDoubleClick.length; i++) {
clearTimeout(timeoutIDForDoubleClick[i]);
}
// code to run on double click
e.preventDefault();
});
Here is my simple solution to prevent the second click. Of course, I could restart the timeout when a double click detected, but in reality I never need it.
clickTimeoutId = null;
onClick(e) {
if (clickTimeoutId !== null) {
// Double click, do nothing
return;
}
// Single click
// TODO smth
clickTimeoutId = setTimeout(() => {
clearTimeout(clickTimeoutId);
clickTimeoutId = null;
}, 300);
}
Summarizing, to recognize the simpleClick and doubleClick events on the same element, just treat the onClick event with this method:
var EVENT_DOUBLE_CLICK_DELAY = 220; // Adjust max delay btw two clicks (ms)
var eventClickPending = 0;
function onClick(e){
if ((e.detail == 2 ) && (eventClickPending!= 0)) {
// console.log('double click action here ' + e.detail);
clearTimeout(eventClickPending);
eventClickPending = 0;
// call your double click method
fncEventDblclick(e);
} else if ((e.detail === 1 ) && (eventClickPending== 0)){
// console.log('sigle click action here 1');
eventClickPending= setTimeout(function() {
// console.log('Executing sigle click');
eventClickPending = 0
// call your single click method
fncEventClick(e);
}, EVENT_DOUBLE_CLICK_DELAY);
// } else { // do nothing
// console.log('more than two clicks action here ' + e.detail);
}
}
You can use debounce to free the single click handler from detecting the double/multiple clicks
Test at: https://jsfiddle.net/L3sajybp/
HTML
<div id='toDetect'>
Click or double-click me
</div>
<hr/>
<ol id='info'>
</ol>
JS
function debounce(func, wait, immediate) {
let timeout;
return function () {
const context = this,
args = arguments;
const later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
function debounceSingleClickOnly(func, timeout = 500) {
function eventHandler (event) {
const { detail } = event;
if (detail > 1) {
console.log('no double click for you '+ func.name);
console.log('');
return;
}
func.apply(this, arguments);
}
return debounce(eventHandler, timeout);
}
window.toDetect.addEventListener('click', debounceSingleClickOnly(handleSingleClick));
window.toDetect.addEventListener('dblclick', handleDoubleClick);
function handleS() {
console.log('S func');
console.log(this.id);
}
function handleSingleClick(event) {
console.log('single click');
const divText = document.createElement('li');
divText.appendChild(document.createTextNode('single click'));
window.info.appendChild(divText)
console.group();
console.log('this element was single-clicked: ' + event.target.id);
console.log(this.id);
console.log('');
console.groupEnd();
}
function handleDoubleClick(event) {
console.log('double click');
const divText = document.createElement('li');
divText.appendChild(document.createTextNode('double click'));
window.info.appendChild(divText);
console.group();
console.log('this element was double-clicked: ' + event.target.id);
console.log(this.id);
console.log('');
console.groupEnd();
}
Output:
const toggle = () => {
watchDouble += 1;
setTimeout(()=>{
if (watchDouble === 2) {
console.log('double' + watchDouble)
} else if (watchDouble === 1) {
console.log("signle" + watchDouble)
}
watchDouble = 0
},200);
}