OK, I am missing something fundamental here I am sure! But for the life of me can not work it out.
Scenario
It's a simple hide show menu;
// Setup hover
var fadeDuration = 200;
var setDelay;
$level1Item.hover(function () {
$(this).addClass('hover').find('.level-2').fadeIn(fadeDuration);
}, function () {
$(this).removeClass('hover').find('.level-2').fadeOut(fadeDuration);
});
And it works fine... but the drop down is rather LARGE and is irritating when it pops up all be it very sexily when you mouse moves from top to bottom of screen.
So I want to set a timeout and clear it on mouse out...
// Setup hover
var fadeDuration = 200;
var setDelay;
$level1Item.hover(function () {
setDelay = setTimeout("$(this).addClass('hover').find('.level-2').fadeIn(200)", 500);
//$(this).addClass('hover').find('.level-2').fadeIn(fadeDuration);
}, function () {
clearTimeout(setDelay);
$(this).removeClass('hover').find('.level-2').fadeOut(fadeDuration);
});
ABSOLUTELY NOTHING HAPPENS!! I have tried alerts in the timeout function and they work... originally the variable fadeDuration was undefined but a number stops the console error.
Try amending the setTimeout call to use an anonymous function:
// Setup hover
var fadeDuration = 200;
var setDelay;
var $item;
$level1Item.hover(function () {
$item = $(this);
setDelay = setTimeout(function() {
$item.addClass('hover').find('.level-2').fadeIn(200)
}, 500);
},
function () {
clearTimeout(setDelay);
$(this).removeClass('hover').find('.level-2').fadeOut(fadeDuration);
});
When the string you pass to setTimeout is eval()ed, this is window and not whatever object you are expecting.
Don't pass strings to setTimeout, and be careful to preserve the value of this.
var self = this;
setDelay = setTimeout(function () {
$(self).addClass('hover').find('.level-2').fadeIn(200);
}, 500);
You can't use this in the setTimeout-code, since this depends on the context. So when the timeout fires, the this is a different this... bad English, but hopefully it makes sense.
Also, avoid using strings in timers; use functions instead. While you can use a string, which is then evaluated as JavaScript, it's generally bad form compared to simply wrapping the same code in a function
var fadeDuration = 200;
var setDelay;
$level1Item.hover(function () {
var element = $(this);
setDelay = setTimeout(function() {
element.addClass('hover').find('.level-2').fadeIn(fadeDuration);
}, 500);
}, function () {
clearTimeout(setDelay);
$(this).removeClass('hover').find('.level-2').fadeOut(fadeDuration);
});
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'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 am attempting to build a somewhat OOP jQuery plugin. Everything is going great, but I can't seem to get the start/pause function to implement correctly. I have the following 2 functions:
this.startAutoPlay = function() {
var interval = setInterval(function() {
obj.gotoNext();
}, config.timing);
};
this.stopAutoPlay = function() {
clearInterval(obj.startAutoPlay);
};
I just need a way to access the interval variable from within the stopAutoPlay function.
Any pointers?
You need to clear the interval that you set.
this.interval;
this.startAutoPlay = function() {
obj.interval = setInterval(function() {
obj.gotoNext();
}, config.timing);
};
this.stopAutoPlay = function() {
clearInterval(obj.interval);
};
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);
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);
}
});