setTimeout and clearTimeout on alternate clicks - javascript

I am trying to create a front-end to a task management system, and I'm stuck on a setTimeout problem. I am trying to make it so that when a user clicks the checkbox, the tile fades to 33% opacity/toggle a "completed" class, waits 2 seconds, and then disappears; if the user clicks again on the checkbox before it disappears, the task should toggle the class and clear the timeout.
I am having a lot of trouble getting the clearTimeout command to work. I have declared my timer variable outside of the relevant blocks, tried adding the clearQueue() and stop() commands to my function, and triple-checked spelling.
My JS fiddle is here: http://jsfiddle.net/sLYA9/.
Here is my relevant JS:
$('#alltasks .taskitem form').click( function ( event ) {
event.preventDefault();
// Variables for different referenced elements
var tile = $( this ).parent('.taskitem');
var taskContents = '<div class=\'taskitem\' draggable=\'true\'>' + tile.html() + '</div>';
var timer;
// Unchecking a checked task
if (tile.hasClass('completed')) {
clearTimeout( timer );
tile.clearQueue().stop().fadeTo( 300, 1 );
} else { // Checking an unchecked task
tile.fadeTo( 300, 0.33 );
timer = setTimeout( function() {
alert("the task disappears");
}, 2000 );
}
tile.toggleClass('completed');
});
Again, I would like the user to be able to click the checkbox again before the 2000 ms timer is up and clear the timer.
Any ideas what I missed?
EDIT: I feel silly now. Moving my timer declaration outside of the click handler function made it work properly.

The scope of the timer is local so each time it is called you have a new scope.
The variable timer needs to be declared outside of the click function.

Your timer scoped in the first "click" function. If you move var timer outside of the click callback it works. You could just check when the timer fires to see if it is still "complete"

Related

jQuery trigger event with delay

I have a situation in which I have a series of buttons on a page. Clicking a button triggers several functions and runs a series of complex calculations.
Then I have what is essentially a "click all" button that will trigger a click event on each button:
$('.myBtn').trigger('click'); // $('.myBtn') returns a list of all buttons
This works fine in most modern browsers, but in IE the trigger('click') takes a long time to run and I often get a 'script is taking too long' error.
Unfortunately, the way things are set up there's no real way to avoid the heavy calculations on click.
So I'm thinking of adding some sort of delay. So on "click all", trigger btn1 click, wait 200ms, trigger btn2 click, wait... etc.
I've tried things like:
$('.btnAll').each(function() {
var el = $(this);
setTimeout(function () {
el.trigger('click');
}, 200);
});
But I don't think this works correctly because of the way .each() calls are queued or something(?). Event queueing and synchronous calls are still a little unclear to me.
Any thoughts on how I can make this work?
.each() calls are not 'queued', they just execute the given function on each element of the collection, one after the other. So you set for each button-click a timeout of 200ms. The result: 200ms later all buttons are triggered at (nearly) same time. If you want to stagger the clicks with delay in between, you must give them different times like so:
$('.btnAll').each(function(i) { // i is index of this in the collection
var el = $(this);
setTimeout(function () {
el.trigger('click');
}, i * 200); // each button gets a multiple of 200ms, depending on its index
});
This triggers the first button immediately, the second 200 ms later, the third.... .
Try it
function myEach(){
$('.btnAll').each(function() {
$(this).trigger('click');
});
}
setTimeout(myEach(),200);

why setInterval() cycle goes faster every time?

I'm building a custom slider on Javascript , and I want that every time the user clicks on a div of the slider, the slider should stop for X seconds.
My code is:
$(document).ready(function () {
var ciclo;
var index_slide = 1;
function startSlidercicle() {
ciclo = setInterval( function() {
// Slider code goes here
}, 3000);
}
//Here I start the slider animation
startSlidercicle();
//When the user clicks on a div called 'slide', stop the cycle and start again the animation cycle
$('.slide').on('click', function() {
clearInterval(ciclo);
setTimeout(startSlidercicle(), 3000);
});
});
But the problem is that everytime I click and stop the slider, the cycle starts faster and faster. How can I fix it?
Instead of:
clearInterval(ciclo);
setTimeout(startSlidercicle(), 3000);
or:
clearInterval(ciclo);
setTimeout(startSlidercicle, 3000);
I changed the code to be:
clearInterval(ciclo);
startSlidercicle();
And now the slider just works fine. I think that, in the first two proposals, every time I click on the div, a new function is created, "overlapping" over the existing cycle and, thus, it looks like the slider speeds up, but its just one cycle starting over another.
You need to change this:
clearInterval(ciclo);
setTimeout(startSlidercicle(), 3000);
to this:
clearInterval(ciclo);
setTimeout(startSlidercicle, 3000);
In your existing code, you are calling startSlidercirle immediately and it is not waiting until the setTimeout() fires because you have the () after the function name. That means to execute it immediately and pass the result of executing that to setTimeout(). You want to just pass the function reference to setTimeout() which is done by just having the name of the function with no () after it. This is a common mistake.

Is there anyway on onmouseover to fire after mouseovering after a few seconds?

I want to make sure the user wants to have something pop up by mouseing over a div. I don't want the user to accidentally trigger something to pop up without intent. setTimeout doesn't work because even if it's very brief, the pop up will still pop up, it's just delayed. What I want is the user to mouseover something for 1sec for a pop up to display.
**update:
When I do this:
<div onmouseover="myTimer=setTimeout('display(this)', 5000);">
the timer works and it is displayed after 5 seconds but this is not passed and I can't get the element via $(element).next(), etc.
When I do this:
<div onmouseover="myTimer=setTimeout(display(this), 5000);">
the timer doesn't work. What is wrong, how can I get the timer and the this to be passed?
Thanks!
**update2: the this problem from here states: "Code executed by setTimeout() is run in a separate execution context to the function from which it was called. As a consequence, the this keyword for the called function will be set to the window (or global) object, it will not be the same as the this value for the function that called setTimeout."
I found the answer to overcome this here where you have to "save a reference to the context where the setTimeout function call is made"
This should work for you:
<div id="example">Hover me</div>
<script type="text/javascript">
(function(){
var timer;
var el = document.getElementById('example');
el.onmouseover = function(){
timer = setTimeout(function(){
display(el);
// If display takes no arguments and uses the "this" keyword inside it
// Use display.call(el); instead
}, 1000);
}
el.onmouseout = function(){
clearTimeout(timer);
}
})();
</script>
Example on JSFiddle
I'm pretty sure that this should works:
onmouseover="myTimer=setTimeout(yourFunctionName, 1000);"
You have also to add:
onmouseout="clearTimeout(myTimer);"
On mouse over you can start a timer. On mouse out reset the timer to 0. If the timer reaches 1s, you can trigger your event and reset the timer to 0.
I also later came across something called the hoverIntent jQuery Plug-in, worth checking out.

Stop duplicate mouse over detection

I have a popup that is executed on mouseover with jquery.
Within that function I have a second delay before the popup displays using settimeout
Problem is if in that second they mouse over multiple times then multiple popups are triggered.
$('#div').mouseover(function() {setTimeout("popup()",1000);});
What I need to do is disable the detection and then re enable it in popup().
How might I do that?
You can use .hover() with a clearTimeout(), like this:
$('#div').hover(function() {
$.data(this, 'timer', setTimeout(popup, 1000));
}, function() {
clearTimeout($.data(this, 'timer'));
});
This clears the timeout you're setting if the mouse leaves, you'll have to stay on the element for a full second for the popup to trigger. We're just using $.data() on the element to store the timer ID (so we know what to clear). The other change is to not pass a string to setTimeout() but rather a reference directly to the function.
I guess something like this
(function(){
var popup_timer = 0;
$('#div').mouseover(function() {
clearTimeout(popup_timer);
popup_timer = setTimeout("popup()",1000);
});
});
EDIT updated code, clearTimeout added, wrapped

Queuing and stop propagating a click event to inside a div in Javascript

I'm trying to implement a "wait for 3 seconds to do this operation" <div>.
So, I have a <div> that has a bunch of elements in it that I want to be unclickable for say 3 seconds (a timer, or some other event), but somehow capture the events in a queue, and then fire them after the period (or some event of my choice) has elapsed/performed?
I'm thinking this is a problem kind of like putting up a modal dialog, and then not having anything beneath it clickable. Am I right in thinking this?
One possibility is to have the click handler for your DIV respond to clicks on its child elements as the event bubbles up. That handler would perform the queuing until the delay elapsed. Here's a rough example (using jQuery event handling for convenience):
(function() {
var isReady = false, queue = [];
setTimeout(function() {
isReady = true;
processQueue()
}, 3000);
$("#mainDiv").click(function(ev) {
if (isReady) {
//code to handle the click based on which child was clicked (ev.srcElement)
} else {
queue.push(ev.srcElement);
}
});
function processQueue() {
var i, elem;
for (i = 0; elem = queue[i]; i++) {
$(elem).click(); //re-trigger the click event
}
queue.length = 0;
}
})();
Give the div an onclick function, which starts off for the first 3 seconds as just holding an array of calls with their events...then after your 3000 millisecond timer is done, run a function that changes the div's onclick, allows things to be edited, and runs the array of events.
Another thing that Ive found to be helpful is the function.
setTimeout("alert('hello')",1250);
So something along the lines of surrounding all of the elements onclick method with a second method that will store that call for as long as you need.
<div onclick=registerClick("normallyDoThis()")></div>
Then you can setup a timer at the beggining of the time to change the Div and execute all the commands. Possibly with the eval command?
setTimeout("changeTheDiv()", 3000);
function changeTheDiv()
{
/*eval() all the items in a list of onclicks youve been storing up */
/*Then go through and parse out the register() from all the onclick methods*/
}
I hope this helps

Categories

Resources