Start/stop function with setInterval - javascript

i've got a simple setInterval function for radio buttons to loop on load.
I would like to add a button, which could start or stop the loop. I've added click function for the function, but don't know how to stop it afterwards.
Here is what i've got so far: jsfiddle
Also, if i click the button more times in a row, loop goes berserker - any help appricieted :)
p.s. I've also checked:
start & stop / pause setInterval with javascript, jQuery and
Javascript loop-problem with setTimeout/setInterval
but i was wondering in the dark on how to use those answers as i'm javascript noob.

Make a reference to your setInterval so you can use clearInterval(yourreference).
To start / stop, you can add an extra boolean variable to toggle start and stop.
var t;
var running = false;
$("#start-stop").click(function(){
clearInterval(t);
running = !running;
if (!running)
return;
t = setInterval(function(){
$('.wrap input')
.eq( ( $('input:checked').index() + 1 ) % 3 )
.prop('checked',true);
},1000);
});
Fiddle

Try
jQuery(function () {
var timer;
$("#start-stop").click(function () {
if (timer) {
clearInterval(timer);
timer = undefined;
} else {
timer = setInterval(function () {
$('.wrap input')
.eq(($('input:checked').index() + 1) % 3)
.prop('checked', true);
}, 1000);
}
});
})
Demo: Fiddle

le solution without clearInterval
jQuery(function () {
var toggle = null;
$("#start-stop").click(function () {
if(toggle == null) {
toggle = false;
setInterval(function () {
if(toggle)
$('.wrap input').eq(($('input:checked').index() + 1) % 3).prop('checked', true);
}, 1000);
}
toggle = !toggle;
});
});
Fiddle HERE

Related

Javascript Countdown Timer w/ Bootstrap Modal Pause

See my code below, I am trying to get the countdown timer to pause when a bs.modal is shown and to resume again once the modal is hidden. This works perfectly if the modal is opened and then closed but if you try to reopen the modal again, the timer just continues. I am probably missing something obvious but am not the best when it comes to JS.
(function countdown(remaining) {
if(remaining === 0) {
location.reload(true);
}
document.getElementById('countdown').innerHTML = remaining;
$(document).on('shown.bs.modal', function(e) {
console.log("modal triggered");
clearTimeout(timeout);
});
$(document).on('hide.bs.modal', function(e) {
console.log("modal closed");
countdown(remaining - 1);
});
timeout = setTimeout(function(){
if(remaining != 0) {
countdown(remaining - 1);
}
}, 1000);
})(300);
It seems the issue with the existing code is a timing problem that results in multiple timeouts getting set simultaneously, some of which can then never be cleared because their id's get lost. It's easy to get into such a situation when you're setting up a new timeout for every iteration. So, as I mentioned, setInterval() is a better choice here. Below is a solution using setInterval(). Also note that it's written so as to ensure that any existing interval is cleared before its id is overwritten (in the function clearAndSetInterval.)
(function (remaining) {
var interval;
var clearAndSetInterval = function () {
clearInterval(interval);
interval = setInterval(function (){
if (remaining <= 0) {
clearInterval(interval);
location.reload(true);
}
document.getElementById('countdown').innerHTML = remaining;
remaining = remaining - 1;
}, 1000);
};
$(document).on('shown.bs.modal', function(e) {
clearInterval(interval);
});
$(document).on('hide.bs.modal', function (e) {
clearAndSetInterval();
});
clearAndSetInterval();
})(300);

Change background images using setTimeout

I have 31 images and I want to display them one after another as the background of a div. I only want it to change when the user hovers over the div. My problem right now is that it just flips through all the images really fast. I am attempting to use setTimeout, but it isn't working. How can I make the delay work?
The name of the div is About_Me_Block and the images are called frame1.gif,frame2.gif ...etc
Here is my code:
function changeImg(counter) {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
}
$(document).ready(function() {
var hoverAnimate = []
"use strict";
$('#About_Me_Block').mouseenter(function() {
hoverAnimate[0] = true;
var counter = 0;
while (hoverAnimate[0]) {
console.log(counter);
setTimeout(changeImg(counter), 1000);
counter++;
if (counter === 32)
hoverAnimate[0] = false;
}
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate[0] = false;
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
setTimeout doesn't wait for the function to end, it works lile threading in other languages.
To achieve a what you want, you need to call setTimeout from the changeImg function.
var counter = 0;
$(document).ready(function() {
var hoverAnimate = []
"use strict";
$('#About_Me_Block').mouseenter(function() {
hoverAnimate[0] = true;
counter = 0;
changeImg();
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate[0] = false;
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
function changeImg() {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
counter++;
if (counter < 32 && hoverAnimate[0]) {
setTimeout(changeImg, 1000);
} else {
hoverAnimate[0] = false;
}
}
the reason they happen all at once is because while statement doesn't have delay, so all setTimeout will be set up at the same time, thus, calling changeImg all at once.
To solve this problem, you can replace setTimeout with setInterval. Instead of using while, you can just call setInterval like
var counter = 0;
var myTimer = setInterval(changeImg, 1000);
and update counter inside changeImg every time it gets called. After looping, don't forget to
clearInterval(myTimer)
It seems you need to read up on how setTimeout works. It essentially places a reminder to run a function after a given amount of milliseconds have passed. So, when you do setTimeout(changImg(counter), 1000) you are calling changImg(counter) which returns undefined. Therein producing this setTimeout(undefined, 1000) which is why it flips really fast.
So, you can use bind to allow the function to be called later with that parameter built in. Also, make sure you remove the reminders once done with clearTimeout.
function changeImg(counter) {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
}
$(document).ready(function() {
var hoverAnimate = false, id;
function loop(counter) {
if(hoverAnimate || counter < 32) {
changeImg(counter);
id = setTimeout(loop.bind(this, counter++), 1000);
}
}
$('#About_Me_Block').mouseenter(function() {
hoverAnimate = true;
id = setTimeout(loop.bind(this, 0), 1000);
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate = false;
// Don't want a reminder for a random counter to wake up.
clearTimeout(id);
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
Two methods for timers - setTimeout and SetInterval (single / repeating)
// setInterval is also in milliseconds
var intervalHandle = setInterval(<yourFuncToChangeImage>,5000);
//this handle loop and make example loop stop
yourelement.yourEvent = function() {
clearInterval(intervalHandle);
};

Why doesn't my mouseOver functions work?

The game is quite simple you click on the start button to begin then move your mouse along the track until you reach the end then the timer stops and shows you the score. If you go out of the track you get a score of zero.
Why don't my mouseOver functions work?
Link to my full code: http://www.codecademy.com/TictacTactic/codebits/AQBK4L/edit
Thank you in advance!
var score = 1000;
var timer = setInterval(countDown(), 1000);
$(document).ready(function() {
$('#start').click(function() {
$('#game').mouseover(function() {
stopTimer();
score = 0
$('#points').html(score)
});
$('#end').mouseover(function() {
stopTimer()
$('#points').html(score)
});
});
});
function countDown() {
score = score - 1;
}
function stopTimer() {
clearInterval(timer);
}
Most events are in lowercase, like mouseover, mouseout etc. There are also others that have capitals, like DOMContentLoaded. Most (if not all) programming languages are case-sensitive, watch out for these.
Try this
var clicked = false;
$('#start').click(function() {
if(!clicked){
clicked = true;
}
});
$("#game").hover(function(){
if(clicked){
stopTimer();
score = 0;
$("#points").html(score);
}
});
$("#end").hover(function(){
if(clicked){
stopTimer();
$("#points").html(score);
}
});
Then later if you don't want the hover event to work just set clicked to false I.E : clicked = false;

Simulating Spinner Number with mousedown

I made a control (numeric spinner up and down), to work in a table:
JSFIDDLE: http://jsfiddle.net/Leandro1981/wn8vd/1/
and I want simulate the "mousedown, increment while mouse button is helding" but I can't do it. I tried to mix it with the following and functional script:
JSFIDDLE: http://jsfiddle.net/Leandro1981/kKW85/
but I couldn't make it.
My last attempt here:
http://jsfiddle.net/Leandro1981/S8Zt9/1/
Maybe the wrong is the
timeout = setInterval(function () {
But I couldn't figure out. I'm using bootstrap 3, so I can't use some JQuery UI plugins...
Any help will be preciated!
Please comment below if you have any question, comment or anything to improve this question, and sorry for my english :)
Please be free to use my code/control in any way.
Thanks and kind regards
Write a factory to set up each control so you get a closure over the variables, now it's just a matter of being able to make it work given the relevant elements. For this, you'll need to
Listen for mousedown on the up and down nodes to set off the changes
Start a timeout loop to keep doing your change
Listen for mouseup on window to ensure you cancel the timeout loop (you may also want to listen for mouseout/loss of focus)
So all together,
function spinFactory(node, up, down) { // I wrote this vanilla :D
var spinning, delta;
window.addEventListener('mouseup', stopSpin);
function spin() {
node.value = +node.value + delta;
spinning = setTimeout(spin, 500);
}
function stopSpin() { // maybe also invoke this on mouseout/loss of focus
window.clearTimeout(spinning);
delta = 0;
}
up.addEventListener('mousedown', function spinUp() {
delta = 1;
spin();
});
down.addEventListener('mousedown', function spinDown() {
delta = -1;
spin();
});
}
// apply to your control, used a bit of jQuery to make life easier
$('.PNET-spinner').each(function () {
spinFactory(
this.getElementsByTagName('input')[0],
$(this).find('.btn:first-of-type')[0],
$(this).find('.btn:last-of-type')[0]
);
});
DEMO
I have updated the Fiddle here ... Please check this and it might helps you..
Script
$('.PNET-spinner .btn:first-of-type').on('mousedown', function (e) {
var timer, proxy = this;
timer = setInterval(function () {
increment(proxy);
}, 200);
$(document).one("mouseup", function () {
increment(proxy);
if (timer) clearInterval(timer);
});
});
$('.PNET-spinner .btn:last-of-type').on('mousedown', function () {
var timer, proxy = this;
timer = setInterval(function () {
decrement(proxy);
}, 200);
$(document).one("mouseup", function () {
decrement(proxy);
if (timer) clearInterval(timer);
});
});
function increment(proxy) {
var numupdown = $('.PNET-spinner input', $(proxy).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
inputValue++;
$(numupdown).val(inputValue);
}
function decrement(proxy) {
var numupdown = $('.PNET-spinner input', $(proxy).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
if (inputValue > 1) {
inputValue--;
$(numupdown).val(inputValue);
}
}
You simply need to take care of two things. First, your function to increment and decrement the value in the textbox should be called again and again till user do mouseout or mouseup. Second, make surethis has the right value in var numupdown = $('.PNET-spinner input', $(this).closest("tr"));
Following code shows how to do it for the increment button. Similar thing, you can implement for decrement button.
var timeout;
var inc = function () {
var myThis = this;
var numupdown = $('.PNET-spinner input', $(this).closest("tr"));
var inputValue = parseInt($(numupdown).val(), 10);
inputValue++;
console.log(inputValue);
$(numupdown).val(inputValue);
clearTimeout(timeout);
timeout = setTimeout(function(){
//http://stackoverflow.com/questions/3630054/how-do-i-pass-the-this-context-to-a-function
inc.apply(myThis, arguments);
}, 1000);
};
var incStop = function(){
clearTimeout(timeout);
}
$('.PNET-spinner .btn:first-of-type').on('mousedown', inc);
$('.PNET-spinner .btn:first-of-type').on('mouseup', incStop);
$('.PNET-spinner .btn:first-of-type').on('mouseout', incStop);
Check this DEMO here.

Repeat code every x seconds but not if [insert check here]

This is a followup to this question, where I found out how to make code be repeated every x seconds. Is it possible to make an event that can change this? I.e. I have a checkbox which is meant to control whether this is repeated or not, so I figured I'd need something like this:
$(checkbox).bind("change", function() {
switch(whether if it is ticked or not) {
case [ticked]:
// Make the code repeat, while preserving the ability to stop it repeating
case [unticked]:
// Make the code stop repeating, while preserving the ability to start again
}
});
I have no idea what I could put in the cases.
You can do it by assigning your setInterval function to a variable.
var interval = setInterval(function() { }, 1000);
and then you can stop setInterval by
clearInterval(interval);
p.s.
to start your interval you need to call var interval = setInterval(function() { }, 1000); again
You can either stop and start the interval:
var timer;
function start() {
timer = window.setInterval(function(){
// do something
}, 1000);
}
function stop() {
window.clearInterval(timer);
}
start();
$(checkbox).bind("change", function() {
if ($(this).is(':checked')) {
start();
} else {
stop();
}
});
Or you can have a flag causing the interval to skip the code:
var enabled = true;
var timer = window.setInterval(function(){
if (!enabled) {
// do something
}
}, 1000);
$(checkbox).bind("change", function() {
enabled = $(this).is(':checked');
});
function fooFunc() {
$('#foo').text(+new Date());
}
var id;
var shouldBeStopped = false;
$('input').change(function() {
if (shouldBeStopped)
clearInterval(id);
else
id = setInterval(fooFunc, 200);
shouldBeStopped = !shouldBeStopped;
});​
Live DEMO

Categories