clearTimeout() outside of function not working properly - javascript

I have this line of code, but it doesn't work, and I'm guessing that my function is the cause of the problem here. Here's my JavaScript:
$(document).ready(function () {
var interval;
function move(ele) {
$(ele).animate({
'background-position-y': '0px'
}, 200, function () {
$(ele).animate({
'background-position-y': '3px'
}, 200, function () {
interval = setTimeout(function () {
move(ele)
}, 3);
});
});
};
$(".up").hover(function () {
move(this), function () {
clearTimeout(interval);
interval = null;
$(this).css("background-position", "80px 3px ");
};
});
Can someone explain me what I'm doing wrong here?

Even with the proper closing braces as suggested by David there is still a problem which keeps the animation going. Clearing the timer (interval) doesn't stop the callback functions passed to .animate() from executing. So interval = setTimeout(...) will still get executed and perpetuated the animation cycle.
I reworked the code a bit for a working example, though there could be some improvements (like getting rid of a global variable). http://jsfiddle.net/aKKRk/

err, it looks like your actual problem is that you're only passing one function to hover, not two. You've got ….hover(function() { move(…), function() { … } }) instead of ….hover(function() { move(…); }, function() { … }).
In the future, this kind of error will be much easier to spot if you make a habit of consistently indenting your code.

Related

Make a Testimonial Scroller Stay on the Screen Before Fading Out

I have a testimonial scroller that shows one testimonial, fades out, shows the next, fades out, and returns to the first.
My issue is that after the fade in animation, the fade out animation begins immediately. It doesn't give enough time for someone to read it.
$(document).ready(function() {
function doFade() {
$("#one").fadeIn(6000,function() {
$("#one").fadeOut(6000).delay(3000);
setTimeout(fadeTwo,6000);
});
}
function fadeTwo() {
$("#two").fadeIn(6000,function() {
$("#two").fadeOut(6000).delay(3000);
setTimeout(fadeThree,6000);
});
}
function fadeThree() {
$("#three").fadeIn(4000,function() {
$("#three").fadeOut(6000).delay(3000);
setTimeout(doFade,6000);
});
}
doFade();
});
jQuery's delay function will only delay functions that are called after it in the chain, so it is having no effect on your code. Delay docs
You need to use it before the call to fadeOut, e.g.
$(document).ready(function() {
function doFade() {
$("#one").fadeIn(6000,function() {
setTimeout(fadeTwo,6000);
})
.delay(3000)
.fadeOut(6000);
}
function fadeTwo() {
$("#two").fadeIn(6000,function() {
setTimeout(fadeThree,6000);
})
.delay(3000)
.fadeOut(6000);
}
function fadeThree() {
$("#three").fadeIn(6000,function() {
setTimeout(doFade,6000);
})
.delay(3000)
.fadeOut(6000);
}
doFade();
});
Edit:
You are currently setting a timeout to execute the next function, within the complete callback of fadeIn. This is a bit confusing to my mind, and I think it is simpler and clearer to do something like the following. In addition, there is no reason to define the three functions within the ready function - it is personal preference but I like to keep the amount of code within a callback to a minimum, such as...
$(document).ready(function() {
doFade();
});
function doFade() {
setTimeout(fadeTwo,12000);
$("#one").fadeIn(6000).delay(3000).fadeOut(6000);
}
function fadeTwo() {
setTimeout(fadeThree,12000);
$("#two").fadeIn(6000).delay(3000).fadeOut(6000);
}
function fadeThree() {
setTimeout(doFade,12000);
$("#three").fadeIn(6000).delay(3000).fadeOut(6000);
}
Edit 2:
In further effort to reduce the amount we repeat ourselves, we can extract the whole animation sequence into a function:
$(document).ready(function() {
doFade();
});
function fadeInThenOut(element) {
element.fadeIn(6000).delay(3000).fadeOut(6000);
}
function doFade() {
setTimeout(fadeTwo,12000);
fadeInThenOut($("#one"));
}
function fadeTwo() {
setTimeout(fadeThree,12000);
fadeInThenOut($("#two"));
}
function fadeThree() {
setTimeout(doFade,12000);
fadeInThenOut($("#three"));
}
Edit 3:
At this point we probably notice how similar our three functions are, and want some way to reduce that repetitiveness. So we could use recursion, and just change which element we pass in each time.
$(document).ready(function() {
doFade();
});
function doFade(elementNumber) {
const elementNumber = elementNumber < testimonialElements.length ? elementNumber : 0;
setTimeout(doFade(elementNumber + 1),12000);
$('#' + testimonialElements[elementNumber]).fadeIn(6000).delay(3000).fadeOut(6000);
}
var testimonialElements = ["one","two","three"];
While this solution may lose something in readability and simplicity, the great advantage is that when you add a fourth testimonial, you don't need to write a function to handle it. All you would do is change the testimonialElements array to include the new element id.

Angular How to use $interval without delay during first run?

I have the following function which is animating some object on the screen:
$interval(function() {
$('#cloudLeftToRight').animate({
left: '+=250%',
}, 7000, function() {
$('#cloudLeftToRight').removeAttr('style');
$scope.resetAnimationCloudLeftToRight();
});
}, 8000);
Problem is that if app function is triggered first animation is displayed after the 8 sec. delay.
I would like to run animation immediately after the function is triggered and after that repeat animation each 8 sec.
It occurred to me one solution:
Make the timer and animation function separated and after init call only animation function and immediately call the timer function where should be passed name of the animation function.
Any better solution please?
Many thanks for any advice.
You could try something like this:
function myFunction(){
$('#cloudLeftToRight').animate({
left: '+=250%',
}, 7000, function () {
$('#cloudLeftToRight').removeAttr('style');
$scope.resetAnimationCloudLeftToRight();
});
}
myFunction();
$interval(function () {
myFunction();
}, 8000);
I think it looks cleanest to use $timeout and recursively call yourself in an immediately invoked function:
(function animate() {
$('#cloudLeftToRight').animate({
left: '+=250%',
}, 7000, function () {
$('#cloudLeftToRight').removeAttr('style');
$scope.resetAnimationCloudLeftToRight();
});
$timeout(animate, 8000);
})()
Maybe this pseudocode helps you
var runAnim = function () {
//here animation code
$timeout(runAnim, INTERVAL);
};
runAnim();

SetInterval using linkObj

With this code I expect to see a 'yo' added to the console every second while I'm hovering over .cell-top. But I get one 'yo' and that's it.
function cellUp(linkObj) {
console.log('yo');
}
$(".cell-top").hover(function() {
setInterval(cellUp($(this)), 1000);
});
Any idea what I can do to get my expected results?
PS. I'm using linkObj to get $(this) in a function within cellDown, I didn't include the function because that's unrelated to the issue I'm having. I did include the linkObj because I figured it may be part of the issue.
Since you're using jQuery, you can use $.proxy.
$(".cell-top").hover(function() {
setInterval($.proxy(cellUp, null, $(this)), 1000);
});
var interval;
function cellUp(linkObj) {
console.log(linkObj);
}
$(".cell-top").hover(function() {
var self = this;
interval = setInterval(function(){cellUp($(self))}, 1000);
},function() {
clearInterval(interval);
});

ClearTimeout dose not work well (may be when clearing before the first timer fire)

I wanted to add a "loading" class to the body element on every ajax call that takes more than 300ms.
so I added the following script to my common.js file:
$(document).ready(function ()
{
var timer;
$("body").on({
ajaxStart: function ()
{
var body = $(this)
var timer = setTimeout(function ()
{
body.addClass("loading");
}, 300)
},
ajaxStop: function ()
{
$(this).removeClass("loading");
clearTimeout(timer);
}
});
});
Now this works if i make the ajax calls at leas 1sec long.
When they are immediate the loading class remains on the body element.
I suspect that the first the ajax call ends before 300ms expires that calls for removing the class and clearing the timer, lets say this takes 10ms, but then the timer the fires after 290ms more...
I wonder how could i test for that?
and weather I'm doing something wrong to achieve the described above task.
P.S
I'm using ASP.NET MVC.
You're redeclaring the variable, loosing the higher scope of the previously declared variable:
$(document).ready(function () {
var timer;
$(document).on({
ajaxStart: function () {
var body = $(document.body);
timer = setTimeout(function () { //don't use the "var" keyword
body.addClass("loading");
}, 300)
},
ajaxStop: function () {
clearTimeout(timer);
$(this).removeClass("loading");
}
});
});

Refactor $(document).ready(), currently have 2 instances

I've got following JavaScript functions but want to refactor the $(document).ready() as I've got 2 instance of it. How can I achieve this?
FlashMessenger = {
init: function() {
setTimeout(function() {
$(".flash").fadeOut("slow", function () {
$(".flash").remove();
});
}, 5000);
}
}
SelectLanguage = {
init: function() {
$('#selectLanguageId').change(function() {
$('#frmSelectLanguage').submit();
});
}
}
$(document).ready(FlashMessenger.init);
$(document).ready(SelectLanguage.init);
It’s perfectly acceptable to set multiple handlers for $(document).ready, although you may have a good reason to do otherwise that I’m not aware of. You might be interested in knowing that $(handler) can be used as shorthand for $(document).ready(handler):
$(FlashMessenger.init);
$(SelectLanguage.init);
If you really want them in one call though, try this:
$(function() {
FlashMessenger.init();
SelectLanguage.init();
});
First off, there's no reason you have to combine them.
But if you want to:
$(document).ready(function(jq){
FlashMessenger.init(jq);
SelectLanguage.init(jq);
});
Breaking it down:
Create a function to do all your init (it can be named or anonymous; the one above is anonymous).
Have it call the other init functions, passing in the jQuery instance that jQuery passes you just in case they use it.
You might choose to wrap each init call in a try/catch block as well, so that errors in one init don't prevent the next init from occuring, but that depends on your needs.
Just combine them into one call with an anonymous function:
$(document).ready(function()
{
FlashMessenger.init();
SelectLanguage.init();
});
$(document).ready(function() {
FlashMessenger.init();
SelectLanguage.init();
});
Option 1
FlashMessenger = {
init: function() {
setTimeout(function() {
$(".flash").fadeOut("slow", function () {
$(".flash").remove();
});
}, 5000);
}
}
SelectLanguage = {
init: function() {
$('#selectLanguageId').change(function() {
$('#frmSelectLanguage').submit();
});
}
}
$(function(){
FlashMessenger.init();
SelectLanguage.init();
});
Option 2
FlashMessenger = {
init: function() {
setTimeout(function() {
$(".flash").fadeOut("slow", function () {
$(".flash").remove();
});
}, 5000);
}
}
SelectLanguage = {
init: function() {
$('#selectLanguageId').change(function() {
$('#frmSelectLanguage').submit();
});
}
}
$(document).ready(function(){
FlashMessenger.init();
SelectLanguage.init();
});
Option 3
You actually don't need those 2 objects since the only hold the init methods, so here's the ultimate solution, in my opinion, unless you use those objects elsewhere.
$(function(){
$('#selectLanguageId').change(function() {
$('#frmSelectLanguage').submit();
});
setTimeout(function() {
$(".flash").fadeOut("slow", function () {
$(".flash").remove();
});
}, 5000);
})
I prefer 2 and 3 for this reason.
I think what the op is saying is, "If in the future I have a third function to be invoked at document.ready, then how do I do it without touching that piece of code?"
If you do not want multiple $(document).ready() calls, you could just create an array called startupHooks and add each method to it:
startupHooks[ startupHooks.length ] = myNewStartupHook;
and your startup script could look like
$(document).ready(function() {
for( var i=0; i<startupHooks.length; i++ ) {
startupHooks[i]();
}
}
I know that is not mighty useful, but if that appeals to you, you can do it this way.
Personally, I'd go with multiple $(document).ready() calls.
Personally I'd go for not using document.ready at all.
If you place the scripts at the end of your html-page(just before the tag) you can just write in any way you like.
Maybe this doesn't work for 0.01% of the scripts but it never failed to work for me.
Positive effect of this is that the initial HTML+CSS rendering goes faster.
You can also read about it on yahoo. http://developer.yahoo.com/performance/rules.html#js_bottom

Categories

Resources