JavaScript Passing Element but Receiving Window? - javascript

I am trying to pass "this" from:
myVar = setInterval("displayDate(this )",1000);
and is passing "div.test" like it should when I step through it, but when receiving it in:
function displayDate(obj){
}
It says that it is "Window"??? Below is the JavaScript I am building. I am trying to build a foundation for classes that trigger events and eventually I am going to be changing the elements.src=".jpg" by a variable rate (now set to 100) through Sprite parsing. But I am currently stuck on this and I don't want to have to insert onmousemove attributes, etc. in the .html code to keep it clean. . . keep in mind this is only my third day writing .html/.css/.js so any help is appreciated!
// This helps create a static variable that isn't polluting the global namespace
var incr = (function () {
var i = 0;
return function(){ return i++; };
})();
// This perform all of the functions that we would like with some error handling
function displayDate(obj){
var counter = incr();
try{
obj.innerHTML=counter;
}catch(err){
var txt="There was an error on this page.\n\n";
txt+="Error description: " + err.message + "\n\n";
txt+="Click OK to continue.\n\n";
alert(txt);
}
}
// This is our trigger that sets an interval for our main Java function
$(function(){
var myVar;
$(".test").hover( function() {
// The mouse has entered the element, can reference the element via 'this'
myVar = setInterval("displayDate(this )",100);
},function () {
// The mouse has left the element, can reference the element via 'this'
clearInterval(myVar);
}
);
});

The time the displayDate function is called, your into another scope and this is your window object (not the div element anymore). To resolve, you can do like this:
$(".test").hover( function() {
var self = this;
myVar = setInterval(function() {
displayDate(self);
},1000);
}, function() {
clearInterval(myVar);
});

instead of setInterval("displayDate(this )",100);
$(".test").hover( function() {
var that = $(this);
setInterval(function () {
displayDate(that);
},100);

Related

How can I end a requestanimationFrame with a function? [duplicate]

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
});

Javascript clearInterval of interval set in another scope

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

Is there a way to cancel requestAnimationFrame without a global variable?

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
});

Interval still firing but inaccessible

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);
});
​

How to pass timeout by reference? Or a better way to implement?

I had this code working previously, but I am not so sure now that I have separated my HTML controls from my jQueryUI Widget.
Currently, the timer starts correctly, but I lose my reference to _refreshTimeout after one tick. That is, after the first tick, unchecking my PlanViewRefreshCheckbox does not stop my timer from running.
I have two JavaScript files, PlanView.js and PlanViewCanvas.js.
PlanView.js looks something like this:
(function ($) {
var _minZoom = -2.0;
var _maxZoom = 2.0;
var _stepZoom = (_maxZoom - _minZoom) / 100;
var _refreshTimeout = null;
var _refreshInterval = 60000; //One minute
$(document).ready(function () {
//Initialize Refresh combo box.
$('#PlanViewRefreshCheckbox').click(function () {
if ($(this).is(':checked')) {
var planViewCanvas = $('#PlanViewCanvas');
//Binding forces the scope to stay as 'this' instead of the domWindow (which calls setTimeout).
_refreshTimeout = setTimeout(function(){planViewCanvas.PlanViewCanvas('refresh', _refreshInterval, _refreshTimeout)}.bind(planViewCanvas), _refreshInterval)
}
else {
clearTimeout(_refreshTimeout);
}
});
}
})(jQuery);
and PlanViewCanvas.js houses a jQueryUI Widget:
(function ($) {
$.widget("ui.PlanViewCanvas", {
//other properties and methods not-relevant to problem declared here.
refresh: function (refreshInterval, refreshTimeout) {
var self = this;
_stage.removeChildren();
self.initialize();
//Binding forces the scope to stay as 'this' instead of the domWindow (which calls setTimeout).
refreshTimeout = setTimeout(function () { self.refresh(refreshInterval, refreshTimeout) }.bind(self), refreshInterval);
},
}
})(jQuery);
Does it seem like I am going about things incorrectly?
EDIT: I think the answer is probably to use setInterval and not setTimeout.
The first problem is that you forgot the underscore
refreshTimeout should be _refreshTimeout
second, your variable needs to be global to be accessible in both files, so declare it outside of the function:
var _minZoom = -2.0;
var _maxZoom = 2.0;
var _stepZoom = (_maxZoom - _minZoom) / 100;
var _refreshTimeout = null;
var _refreshInterval = 60000; //One minute
(function ($) {
....
})(jQuery)
You can't pass values by reference. I see two options:
pass an Object. If you have it referenced from two variables, you can access its properties in both scopes.
split up you functionality in two functions, where it belongs: One masters the interval loop and triggers the refresh function, and the other does things to refresh. The refreshTimeout variable only belongs to the scope of the first one. point. You may add the interval function to you widget if it is often needed.
The answer was very 'oh derp.'
//Initialize Refresh combo box.
$('#PlanViewRefreshCheckbox').click(function () {
if (this.checked) {
_refreshTimeout = setInterval(function(){$('#PlanViewCanvas').PlanViewCanvas('refresh')}, _refreshInterval)
}
else {
clearTimeout(_refreshTimeout);
}
});

Categories