Jquery .delay().fadeOut cancel/clear queue.. Is it possible? How? - javascript

I need some help here..
Is it possible to cancel the chaining delay?
Mn.Base.TopBox.show = function(timedur){
$('#element').fadeIn().delay(timedur).fadeOut();
}
Mn.Base.TopBox.cancelFadeout = function(){
}
I read about queuing and tried some different approaches but I hadn't success...
$('#element').stop();
$('#element').queue('fx', []);
Thanks in advance,
Pedro

It isn't, .delay() doesn't play well with anything else since the timer keeps ticking and a .dequeue() is executed when it's up...regardless of if you cleared the queue and added a whole new one.
It's better to use setTimeout() directly if you intend to cancel, for example:
Mn.Base.TopBox.show = function(timedur){
$('#element').fadeIn(function() {
var elem = $(this);
$.data(this, 'timer', setTimeout(function() { elem.fadeOut(); }, timedur));
});
}
Mn.Base.TopBox.cancelFadeout = function(){
clearTimeout($('#element').stop().data('timer'));
}
What this does is set the timer and store it using $.data(), and when clering the animations, we're both calling .stop() to stop anything in process, and stopping that timer.
There's still the potential here for issues if you're firing this very rapidly, in which case you'd want to switch to storing an array of delays, and clear them all.

Related

Script fires too much?

Hey so I'm quite a noob but I was wondering if the script below didn't fire too much? And if so, can someone help me optimise it?
<script>
jQuery(function() {
jQuery(window).scroll(function() {
if((jQuery(".main-content").height() - jQuery(window).scrollTop()) < 702) {
jQuery("h1.product-single__title, .product-single__title.h1").addClass('titleScroll');
jQuery("#ProductPhotoImg").addClass('imgScroll');
jQuery("div#option_total").addClass('optionScroll');
jQuery(".template-product .product-form__item--submit, .template-product .product-form__item--quantity").addClass('addScroll');
}
else {
jQuery("h1.product-single__title, .product-single__title.h1").removeClass('titleScroll');
jQuery("#ProductPhotoImg").removeClass('imgScroll');
jQuery("div#option_total").removeClass('optionScroll');
jQuery(".template-product .product-form__item--submit, .template-product .product-form__item--quantity").removeClass('addScroll');
}
});
});
</script>
Thanks
From https://dannyvankooten.com/delay-scroll-handlers-javascript/
var timer;
$(window).scroll(function() {
if(timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function() {
// actual callback
console.log( "Firing!" );
}, 100);
});
What you're looking for is called "throttling". By throttling a function, it only get's triggered x times per second, where you can define x. There are multiple ways of going about this and also a lot of libraries offer this functionality. You can find a nice read here on CSS-tricks which focusses on the lodash implementation.
Another great way to save performance is using requestAnimationFrame() (MDN). This way you don't have to listen to scroll events, but you can tell the browser to perform some script on the next repaint. You could use it like so:
function doThis(){
// javascript you'd like to trigger
window.requestAnimationFrame(doThis); // call again to create a 'loop'
}
window.requestAnimationFrame(doThis); // initial call to get the 'loop' started

Alternative action if event does not occur javascript/jquery

I have a probably really simple question but did not find anything about this or maybe did not find the right words for my problem.
If have a function to be executed on keypress which also changes my variable A - fine, and it works.
But now I want to give an alternative value to my variable A if the keypress event is not happening.
So I'm looking for the correct command for the naive logic of
if ("keypress event happens") {
A = 1
} else {
A = 2
}
Is there any way to do that in js or jquery with simple true/false checks for the key event?
I've been trying and trying and it did not work once.
Usually, the way one solves this problem is with a setTimeout(). You set the timer for N seconds. If the keypress happens, you cancel the timer. If the keypress doesn't happen, the timer will fire giving you your alternate event.
You probably wrap this in some sort of function that you can trigger whenever you want, but you didn't share the overall context so this is just the general idea:
$("#myObj").keypress(function(e) {
if (timer) {
clearTimeout(timer);
}
// process key
});
var timer = setTimeout(function() {
timer = null;
// key didn't happen within the alltoted time so fire the alternate behavior
}, 5000);

How to stop a delay if attribute is clicked

Testing this out and I'm trying to figure out how to stop a delay if i click another attribute. I'll post the site address to make this explanation a lot better, but basically when you press menu my nav appears with a delay, when I press Assignment 6 I want everything else to hide, which it does, but I see that because I have a delay when it hides and it's not done delaying it will continue to print out the rest of the elements even though they are supposed to be hidden. Also a disclaimer, I've gotten a lot of heat on this site before because I think people think I expect an answer. This is not the case, I love to learn and although the answer would be helpful and I would be able to de-engineer it and learn it, I would much rather have some guidance. So yeah, I'm not just looking for an answer if anyone thinks that's what I'm on here for (I come on here when I can't figure it out any other way).
site
my jQuery script:
$(document).ready(function () {
//$('ul').hide();
$('ul li').hide();
$('nav>li').hide();
$('nav>h1>').click(function (event) {
event.preventDefault();
$('nav>ul li:hidden').each(function(i) {
$('nav>li').show();
$('nav>h1').hide();
$(this).delay(i*600).fadeIn(200);
});
$('nav>ul li:visible').each(function(i) {
$('nav>h1').hide();
$(this).delay(i*600).fadeOut(200);
});
return false;
}); //closes a.btnDown
$('nav>li').click(function (event) {
$('nav>h1').show();
$('nav>li').hide();
$('ul li').hide();
return false;
}); //closes a.btnDown
}); //closes .ready
setTimeout is a useful mechanism to solve what you are after. It waits for (at least) the delay specified, and executes the callback function.
var elements = $('nav>ul li:hidden');
var timeoutId;
function doAnimation(index) {
timeoutId = window.setTimeout(function () {
if (index < elements.length) {
$(elements[index]).fadeIn(200);
doAnimation(++index);
}
}, 600);
}
The clue is to declare the timeoutId outside a recursive function, and assign it within the function. By doing it in a recursive fashion, you don't start the next timeout before the current timeout is finished, and it can be aborted at any time.
window.clearTimeout(timeoutId);
I've made a little fiddle that demonstrates the concept, but I haven't implemented a complete solution. Hope this helps you get further with your project.
http://jsfiddle.net/pyMpj/
You can replace your delays with setTimeout and clear them with clearTimeout
$('nav>ul li:hidden').each(function(i) {
$('nav>li').show();
$('nav>h1').hide();
var fadeTimeout = setTimeout(function () {
$(this).fadeIn(200);
}, i * 600);
});
$('nav>li').click(function (event) {
$('nav>h1').show();
$('nav>li').hide();
$('ul li').hide();
clearTimeout(fadeTimeout);
return false;
});

Do I have to clear setTimeouts after they've run?

Simple question really, I'm running a bunch of timeouts but wanna make sure they don't slow the page down and that for some reason they aren't kept in memory after they've executed.
$projects.each(function(index) {
var $this = $(this);
window.setTimeout(function() {
// animate
}, 300 * index);
});
// Clear timeouts?
My guess is that they're destroyed once they've run but just want to follow best practice.
No, you don't. Interval timers (via "setInterval()"), yes, if you want them to stop.
It's harmless to clear a timeout that doesn't have to be cleared. That is, if you do clear one after it has run, browsers won't complain.

When using setInterval, if I switch tabs in Chrome and go back, the slider goes crazy catching up

I have a jQuery slider on my site and the code going to the next slide is in a function called nextImage. I used setInterval to run my function on a timer, and it does exactly what I want: it runs my slides on a timer. BUT, if I go to the site in Chrome, switch to another tab and return, the slider runs through the slides continuously until it 'catches up'. Does anyone know of a way to fix this. The following is my code.
setInterval(function() {
nextImage();
}, 8000);
How to detect when a tab is focused or not in Chrome with Javascript?
window.addEventListener('focus', function() {
document.title = 'focused';
},false);
window.addEventListener('blur', function() {
document.title = 'not focused';
},false);
To apply to your situation:
var autopager;
function startAutopager() {
autopager = window.setInterval(nextImage, 8000);
}
function stopAutopager() {
window.clearInterval(autopager);
}
window.addEventListener('focus', startAutopager);
window.addEventListener('blur', stopAutopager);
Note that in the latest version of Chromium, there is either a bug or a 'feature' which is making this less reliable, requiring that the user has clicked at least once anywhere in the window. See linked question above for details.
I post an answer here: How can I make setInterval also work when a tab is inactive in Chrome?
Just do this:
setInterval(function() {
$("#your-image-container").stop(true,true);
nextImage();
}, 1000);
inactive browser tabs buffer some of the setInterval or setTimeout functions.
stop(true,true) - will stop all buffered events and execute immadietly only last animation.
The window.setTimeout() method now clamps to send no more than one timeout per second in inactive tabs. In addition, it now clamps nested timeouts to the smallest value allowed by the HTML5 specification: 4 ms (instead of the 10 ms it used to clamp to).
A few ideas comes to mind:
Idea #1
You can make it so that a short burst is idempotent. For example, you could say:
function now() {
return (new Date()).getTime();
}
var autopagerInterval = 8000;
function startAutopager() {
var startImage = getCurrentImageNumber();
var startTime = now();
var autopager = setInterval(
function() {
var timeSinceStart = now() - startTime();
var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
if (getCurrentImageNumber() != targetImage)
setImageNumber(targetImage); // trigger animation, etc.
},
autopagerInterval
);
return autopager;
}
This way even if the function runs 1000 times, it will still run in only a few milliseconds and animate only once.
note: If the user leaves the page and comes back, it will have scrolled. This is probably not what the original poster wants, but I leave this solution up since it is sometimes what you want.
Idea #2
Another way to add idempotence (while still keeping your nextImage() function and not having it scroll to the bottom of the page) would be to have the function set a mutex lock which disappears after a second (cleared by another timeout). Thus even if the setInterval function was called 1000 times, only the first instance would run and the others would do nothing.
var locked = false;
var autopager = window.setInterval(function(){
if (!locked) {
locked = true;
window.setTimeout(function(){
locked=false;
}, 1000);
nextImage();
}
}, 8000);
edit: this may not work, see below
Idea #3
I tried the following test:
function f() {
console.log((new Date()) + window.focus());
window.setTimeout(f, 1000);
}
f();
It seems to indicate that the function is being called every second. This is odd... but I think this means that the callbacks are being called, but that the page renderer refuses to update the page in any graphical way while the tab is unfocused, delaying all operations until the user returns, but operations keep piling up.
Also the window.focus() function doesn't say if the window has focus; it GIVES focus to the window, and is thus irrelevant.
What we want is probably this: How to detect when a tab is focused or not in Chrome with Javascript? -- you can unset your interval when the window loses focus (blur), and reset it when it gains focus.
I don't know exactly what is going on in your function nextImage(), but I had a similar issue. I was using animate() with setInterval() on a jQuery image slider that I created, and I was experiencing the same thing as you when I switched to a different tab and back again. In my case the animate() function was being queued, so once the window regained focus the slider would go crazy. To fix this I just stopped the animate() function from queuing.
There are a couple ways you can do this. the easiest is with .stop(), but this issue and ways to fix it are documented in the jQuery docs. Check this page near the bottom under the heading additional notes: http://api.jquery.com/animate/
I had faced similar issue, somehow this code below works fine for me.
var t1= window.setInterval('autoScroll()', 8000);
window.addEventListener('focus', function() {
focused = true;
window.clearInterval(t1);
t1 = window.setInterval('autoScroll()', 8000);
},false);
window.addEventListener('blur', function() {
focused = false;
window.clearInterval(t1);
},false)
function autoScroll()
{
if ( running == true){
if ( focused = true){
forwardSlide();
}
}
else {
running = true;
}
}
If you are using Soh Tanaka's image slider then just add this...to solve your Google Chrome issue:
$(".image_reel").stop(true, true).fadeOut(300).animate({ left: -image_reelPosition}, 500 ).fadeIn(300);
Take note of the .stop() function. Ignore the fading in and out stuff, that's what I used on my version
Thanks
Seconding the comment by jgerstle to use page visibility events instead, see https://www.w3.org/TR/page-visibility/#example-1-visibility-aware-video-playback for more around subscribing to 'visibilitychange' for hidden/visible states.
This seems to be more useful than focus/blur these days as it covers visible-but-not-selected windows if concerned also about multi-window operating systems.

Categories

Resources