I have this div box which calls a function "nextStep" onclick.
function nextStep() {
console.log("NEXT");
}
<div onclick="nextStep()">test</div>
Problem is, if I double click the div box the function will call twice.
That should not be possible.
How can I disallow this?
You can use the time to lock your double click.
Run snippet. If the previous click was less than 0.3 seconds ago, the click will be blocked. You can adjust the amount of time as needed.
function nextStep() {
var $div = $(".test");
if (!$div.data('lockclick') || +new Date() - $div.data('lockclick') > 300) {
console.log("NEXT");
}
$div.data('lockclick', +new Date());
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="test" onclick="nextStep()">Test</div>
As tagged jquery, you can use jquery's .one method to only allow it to be clicked once.
$("#mydiv").one("click", nextStep);
function nextStep() {
console.log("NEXT")
}
#mydiv { cursor: pointer }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mydiv">click me</div>
Other alternatives including adding a class with pointer-events:none;
use the event listener 'dblclick' in native javascript
const myDiv= document.querySelector('#my-div');
myDiv.addEventListener('dblclick', function (e) {
console.log('in double click')
});
#my-div{
width:200px;
height:200px;
background: black;
}
<div id='my-div'>test</div>
Here's how to do it in FP style
const once = f => {
let called = false;
return () => {
if (called) return;
called = true
f();
}
}
function nextStep() {
console.log("NEXT");
}
const nextStepOnce = once(nextStep)
<div onclick="nextStepOnce()">test</div>
To avoid the triggering on double click you can save the "clicked" status in a variable and ask for it before executing the function code.
If you want to use the onclick listener again (with single click) you can reset the variable after a short time (300ms should be enough for preventing the double click).
let clicked = false;
function nextStep() {
if (!clicked) {
clicked = true;
console.log("NEXT");
}
setTimeout(function(){
clicked = false;
}, 300);
}
<div onclick="nextStep()">test</div>
I want to call a function depending upon the direction of scroll i.e if we scroll down it call goDown() and if we scroll up then call goUp().
Here is my code :
$('.container').on('DOMMouseScroll mousewheel', function (e) {
if(e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) {
console.log('down');
goDown();
} else {
console.log('up');
goUp();
}
return false;
});
But if we scroll it is firing goDown() or goUp() multiple times which is not as I wanted, I just want to fire it once per scroll.
Use lodash's throttle.
In the example below, 1000 (1s) is the time which has to pass without any call to onScroll() before it can fire it again.
$('.container').on(
'DOMMouseScroll mousewheel',
_.throttle(
onScroll,
1000,
{trailing: false}
)
);
// your original function, named:
function onScroll (e) {
if(e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) {
console.log('scrolled down');
// goDown();
} else {
console.log('scrolled up');
// goUp();
}
return false;
}
.container {
height: 200vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container"></div>
If you want to fire onScroll() at the end of your wait period, not at start, use
{leading:false,trailing:true}
...as options (last param).
Also note there's a jQuery plugin for throttle and debounce but I never used it. What I know is that it has a slightly different syntax/approach to each (than _). Feel free to look into it if you don't want to load Lodash in your project.
you can make it with an timeout.
this is my oneliner
t=onscroll=e=>clearTimeout(t,t=setTimeout('console.log("finished")',500))
or with a few more lines:
var scrollWait,
scrollFinished = () => console.log('finished');
window.onscroll = () => {
clearTimeout(scrollWait);
scrollWait = setTimeout(scrollFinished,500);
}
This codes wait for 500ms an then fire finished.
You can translate this to your own situation.
I solved the problem in this way (please note that code should be optimized):
$(document).ready(function(){
var valid = true;
var power = 0; // <-- initial power
setInterval(function(){
if (power>0){
power=power/2; // <-- decrease power every 250ms
if (power<1) power=0;
console.log(power); // <-- you may remove this
}
},250);
$('.container').on('DOMMouseScroll mousewheel', function (e) {
e.preventDefault();
var c_power = Math.abs(e.originalEvent.wheelDeltaY)+Math.abs(e.originalEvent.wheelDeltaX); // <-- get current power
/* event is considered valid only if current power > power */
if (c_power>=power){
power=c_power;
valid=true;
}
if(valid && (e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0)) {
console.log('down');
goDown();
} else {
console.log('up');
goUp();
}
return false;
});
});
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've been working on this jQuery effect heres the fiddle:
http://jsfiddle.net/abtPH/26/
Everything's pretty good so far, however when I click on the elements too fast it seems to get buggy and get weird behavior. If you take your time and click on the elements it works fine.
I've tried using :animate
stuff to make sure the animation ends before the user can click on the next one. I do not like this approach though because from a end user it seems like the effects are laggy. I want the user to be able to click on the elements fast and have the desired effect.
Here's my jQuery so far:
$('li').on('click', function (e) {
e.preventDefault();
var active = $(this).siblings('.active');
var posTop = ($(this).position()).top;
if (active.length > 0) {
var activeTop = (active.position()).top;
if (activeTop == posTop) {
$(this).find('.outer').fadeIn('medium', function () {
active.toggleClass('active', 400).find('.outer').fadeOut('medium');
});
} else {
$(this).siblings('.active').toggleClass('active', 400).find('.outer').slideToggle();
$(this).find('.outer').slideToggle();
}
} else {
$(this).find('.outer').slideToggle();
}
$(this).toggleClass('active', 400);
});
$('.outer').on('click', function (e) {
return false;
});
Use .finish() complete all the queued animation before beginning a new one
$('li').on('click', function(e){
e.preventDefault();
var active = $(this).siblings('.active');
var posTop = ($(this).position()).top;
if (active.length > 0) {
var activeTop = (active.position()).top;
if (activeTop == posTop) {
$(this).find('.outer').finish().fadeIn('medium', function(){
active.finish().toggleClass('active', 400).find('.outer').finish().fadeOut('medium');
});
} else {
$(this).siblings('.active').finish().toggleClass('active', 400).find('.outer').finish().slideToggle();
$(this).find('.outer').finish().slideToggle();
}
} else {
$(this).find('.outer').finish().slideToggle();
}
$(this).finish().toggleClass('active', 400);
});
$('.outer').on('click', function(e){
return false;
});
Demo: Fiddle
I have written this code which fades out the navigation menu to 50% opacity when the mouse is dormant:
var hidden, fadenav, dimNav = function () {
hidden = true;
$('#main-nav').animate({'opacity': 0.5}, 200);
};
$('document').ready(function () {
dimNav();
$('body').on('mousemove', function (e) {
if (hidden) {
$('#main-nav').animate({'opacity': 1}, 200);
hidden = false;
}
if (fadenav !== null) {
clearTimeout(fadenav);
}
fadenav = setTimeout(dimNav, 500);
});
});
What I want to do is make it so that it doesn't fade when the user has their mouse over the #main-nav element.
I have tried this to no avail:
$('#main-nav').on('mouseover mouseout', function (e) {
if (e.type === 'mouseover') {
clearTimeout(fadenav);
} else {
fadenav = setTimeout(dimNav, 500);
}
});
does anyone have any idea how to do this?
Well this certainly is not less code but it may be a bit more straight forward:
$('#main-nav').on('mousemove',function(e){
if(hidden){
$('#main-nav').animate({'opacity': 1}, 200);
hidden = false;
}
clearTimeout(fadenav);
e.stopPropagation();
});
add that instead of:
$('#main-nav').on('mouseover mouseout', function (e) {
if (e.type === 'mouseover') {
clearTimeout(fadenav);
} else {
fadenav = setTimeout(dimNav, 500);
}
});
you don't have to play with classes at all.
Here is my working sample: http://jsfiddle.net/TbwSA/1
EDIT: I realized that you don't even need the mouseout event.
I discovered the solution myself and thought it might be worth other people knowing:
first, you need to do something similar to this:
$('#main-nav').on('mouseover', function (e) {
if (!$('#main-nav').hasClass('hovered')) {
$('#main-nav').addClass('hovered');
}
}).on('mouseout', function () {
if ($('#main-nav').hasClass('hovered')) {
$('#main-nav').removeClass('hovered');
}
});
and then change the dimNav() function to this:
dimNav = function() {
if (!$('#main-nav').hasClass('hovered')) {
hidden = true;
$('#main-nav').css('opacity', '0.5');
}
};
If anyone can think of a better method than this, please contribute!