Still getting the hang of javascript and am not sure how I do this..
I am using intervals to send error and success messages on a page and have run into some issues.
Let's say I have a the following:
function setMyInterval(element) {
var timer = setInterval(function() {
// add some child nodes to element
// play with the css
}, 20);
return timer;
}
function callMyInterval() {
var parent = document.getElementById("element");
var myIntervalRef;
if(!parent.firstChild) {
myIntervalRef = setMyInterval(parent);
} else {
clearInterval(myIntervalRef);
while(parent.firstChild) {
parent.removeChild(parent.firstChild);
}
myIntervalRef = setMyInterval(parent);
}
}
<button onclick="callMyInterval();" >Reset</button>
How would I clear the interval in this case? I have tried a few variations of above, but not successful. I think the problem is due to myIntervalRef not having a reference to the previous call of the function, but not sure how to correct this.
Thanks to all in advanced!!!
You need to define the interval variable outside of the function scope so that subsequent calls to the callMyInterval will refer to the same instance.
You have defined it in the local scope of the function so every call to callMyInterval will refer to a new variable instance so you will not get reference to the previous timer.
var myIntervalRef;
function callMyInterval() {
var parent = document.getElementById("element");
if (parent.firstChild) {
clearInterval(myIntervalRef);
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
}
myIntervalRef = setMyInterval(parent);
}
Simple, move your myIntervalRef outside as a globally accessible function will do. Doing so will allow other functions to access it and make changes to it.
// Moving the function reference outside of the method, so other function can access it.
var myIntervalRef;
function setMyInterval(element) {
var timer = setInterval(function() {
// add some child nodes to element
// play with the css
}, 20);
return timer;
}
function callMyInterval() {
var parent = document.getElementById("element");
if(!parent.firstChild) {
myIntervalRef = setMyInterval(parent);
} else {
clearInterval(myIntervalRef);
while(parent.firstChild) {
parent.removeChild(parent.firstChild);
}
myIntervalRef = setMyInterval(parent);
}
}
<button onclick="callMyInterval();" >Reset</button>
Hope this helps.
In your code:
var myIntervalRef;
Is local variable of your function, make it global is fastest way to fix
Related
I'm trying to cancel a requestAnimationFrame loop, but I can't do it because each time requestAnimationFrame is called, a new timer ID is returned, but I only have access to the return value of the first call to requestAnimationFrame.
Specifically, my code is like this, which I don't think is entirely uncommon:
function animate(elem) {
var step = function (timestamp) {
//Do some stuff here.
if (progressedTime < totalTime) {
return requestAnimationFrame(step); //This return value seems useless.
}
};
return requestAnimationFrame(step);
}
//Elsewhere in the code, not in the global namespace.
var timerId = animate(elem);
//A second or two later, before the animation is over.
cancelAnimationFrame(timerId); //Doesn't work!
Because all subsequent calls to requestAnimationFrame are within the step function, I don't have access to the returned timer ID in the event that I want to call cancelAnimationFrame.
Looking at the way Mozilla (and apparently others do it), it looks like they declare a global variable in their code (myReq in the Mozilla code), and then assign the return value of each call to requestAnimationFrame to that variable so that it can be used any time for cancelAnimationFrame.
Is there any way to do this without declaring a global variable?
Thank you.
It doesn't need to be a global variable; it just needs to have scope such that both animate and cancel can access it. I.e. you can encapsulate it. For example, something like this:
var Animation = function(elem) {
var timerID;
var step = function() {
// ...
timerID = requestAnimationFrame(step);
};
return {
start: function() {
timerID = requestAnimationFrame(step);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation = new Animation(elem);
animation.start();
animation.cancel();
timerID; // error, not global.
EDIT: You don't need to code it every time - that's why we are doing programming, after all, to abstract stuff that repeats so we don't need to do it ourselves. :)
var Animation = function(step) {
var timerID;
var innerStep = function(timestamp) {
step(timestamp);
timerID = requestAnimationFrame(innerStep);
};
return {
start: function() {
timerID = requestAnimationFrame(innerStep);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation1 = new Animation(function(timestamp) {
// do something with elem1
});
var animation2 = new Animation(function(timestamp) {
// do something with elem2
});
I have a function that will continuously reset every time a button is clicked, however, I am trying to clear that timer when a certain picture is on the screen. There are more things going on in the program but this is the general problem I am having. Here is what I have so far:
JavaScript:
function reset() {
var f = document.getElementById("ff").onclick;
var ft = setTimeout(function(){ dontf() }, 3000);
f = ft;
}
function dontf() {
document.getElementById("r").src="H.jpg";
}
function s() {
if (document.getElementById("r").src == "file:///C:/Users/S.jpg") {
clearTimeout(ft);
}
}
HTML
<button onclick="reset(); s();" id="ff">Fd</button>
You can look at this mate
All you needed to do is define var ft in a scope which is accessible by both of the dontf and s funtion
let timer;
function reset() {
const element = document.getElementById("resetButton");
timer = setTimeout(function(){ addImageFunc() }, 3000);
}
function addImageFunc() {
console.log(timer); document.getElementById("addImage").src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
function stopReset() {
if (document.getElementById("addImage").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
clearTimeout(timer);
}
}
<html>
<body>
<button onclick="reset(); stopReset();" id="resetButton">Fd</button>
<img id='addImage'>
</body>
</html>
Suggestions
Use proper naming convention for the variables and functions which will make your code more readable and easy debugging.
Don't use var. use let or const.
Try avoid using global scope variables unless there is no alternate way.
The scope of ft is unreachable since it is defined inside of a function. Need to move it to a scope where the other method is able to reference it.
var ft; // define it outside
function reset() {
// var f = document.getElementById("ff").onclick; <<-- no clue what this is doing
if (ft) window.clearTimeout(ft); // if it is running, remove it
ft = setTimeout(dontf, 3000);
// f = ft; <-- does not make sense
}
function dontf() {
document.getElementById("r").src="H.jpg";
}
function s() {
if (document.getElementById("r").src == "file:///C:/Users/S.jpg") {
if (ft) clearTimeout(ft);
}
}
I'm trying to cancel a requestAnimationFrame loop, but I can't do it because each time requestAnimationFrame is called, a new timer ID is returned, but I only have access to the return value of the first call to requestAnimationFrame.
Specifically, my code is like this, which I don't think is entirely uncommon:
function animate(elem) {
var step = function (timestamp) {
//Do some stuff here.
if (progressedTime < totalTime) {
return requestAnimationFrame(step); //This return value seems useless.
}
};
return requestAnimationFrame(step);
}
//Elsewhere in the code, not in the global namespace.
var timerId = animate(elem);
//A second or two later, before the animation is over.
cancelAnimationFrame(timerId); //Doesn't work!
Because all subsequent calls to requestAnimationFrame are within the step function, I don't have access to the returned timer ID in the event that I want to call cancelAnimationFrame.
Looking at the way Mozilla (and apparently others do it), it looks like they declare a global variable in their code (myReq in the Mozilla code), and then assign the return value of each call to requestAnimationFrame to that variable so that it can be used any time for cancelAnimationFrame.
Is there any way to do this without declaring a global variable?
Thank you.
It doesn't need to be a global variable; it just needs to have scope such that both animate and cancel can access it. I.e. you can encapsulate it. For example, something like this:
var Animation = function(elem) {
var timerID;
var step = function() {
// ...
timerID = requestAnimationFrame(step);
};
return {
start: function() {
timerID = requestAnimationFrame(step);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation = new Animation(elem);
animation.start();
animation.cancel();
timerID; // error, not global.
EDIT: You don't need to code it every time - that's why we are doing programming, after all, to abstract stuff that repeats so we don't need to do it ourselves. :)
var Animation = function(step) {
var timerID;
var innerStep = function(timestamp) {
step(timestamp);
timerID = requestAnimationFrame(innerStep);
};
return {
start: function() {
timerID = requestAnimationFrame(innerStep);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation1 = new Animation(function(timestamp) {
// do something with elem1
});
var animation2 = new Animation(function(timestamp) {
// do something with elem2
});
I have this function.
function changeFrame(){
var time = setInterval(start, 250);
}
and I want to stop it from firing in another function, but haven't been able to figure out how to do it.
Do you mean this?
function changeFrame(){
var time = setInterval(function() {
// Do stuff
}, 250);
}
Think it's in the comments.
Ok amended the fiddle to do what you want. I made time a global var. Call clearInterval in stop with the global var http://jsfiddle.net/QNWF4/3/
In order to call clearInterval you need to have the handle returned by setInterval. That means something will either be global to the page or global to a containing function in which your script resides.
function Timer()
{
var handle = null;
this.start = function (fn,interval) {
handle = setInterval(fn,interval);
};
this.stop = function ()
{
if (handle) { clearInterval(handle); handle = null; }
};
return this;
}
I have a variable created with setInterval called cycle1. It is created with setInterval inside of a prototyped function to an object called eGi, which is the same as $_. After creating it, it still fires, but is inaccessible to the rest of the script and the console. When I try to clear this interval from another prototyped function, nothing happens.
eGi.prototype.startGame = function() {
//other code...
if (somethingOrOther) {
var somethingElse = confirm("start interval?");
if (somethingElse) {
this.cycle1 = setInterval($_.cycle,toMS(INTERVAL_SECONDS));
}
} else {
this.cycle1 = setInterval($_.cycle,toMS(INTERVAL_SECONDS));
}
};
then when i try and stop it in another function
eGi.prototype.gameOver = function() {
clearInterval(this.cycle1);
//other code...
if (restart) {
$_.startGame();
} else {
$_.mainMenu();
}
};
It never gets cleared, and seems to be created again in the calling of $_.startGame. I can't even access it from the Chrome console using $_.cycle1 or the eGi instance variable, egi.cycle1. The strange thing is, this works for accessing any other variable that belongs to my eGi object:
var eGi = function(console,cDom,ctxt,game,devMode) {
$_ = this;
this.game = game;
this.cDom = cDom; //specifically, these objects control the canvas' DOM
this.ctxt = ctxt; //and the CanvasRenderingContext2D
}
eGi.prototype.mainMenu = function() {
this.ctxt.fillText("Hello",250,250); //this works just fine
//etc
};
Why isn't it being cleared?
Full code/game here.
It's a nice game...
The problem is you are referring to "this" inside gameover which doesn't contain reference to cycle1 (undefined).
Instead you have to store "cycle1" as part of an object which can be referenced from your other function (in this case gameover)
Making variables as global is not a good thing. Instead you can store the "cycle1" as part of eGi or any such namespace or object.
Refer here (working code): JSFiddle implementation
Javascript code (start and stop are input buttons)
var eGi = {};
$('#start').click(function start() {
var somethingElse = confirm("start interval?");
if (somethingElse) {
eGi.cycle1 = setInterval(function(){
console.log('Running...');
},1000);
}
});
$('#stop').click(function stop(){
clearInterval(eGi.cycle1);
});