Why shouldn't I use delay? [duplicate] - javascript

According to jQuery document on .delay(),
The .delay() method is best for delaying between queued jQuery
effects. Because it is limited—it doesn't, for example, offer a way to
cancel the delay—.delay() is not a replacement for JavaScript's native
setTimeout function, which may be more appropriate for certain use
cases.
Could someone please expand on this? When is it more appropriate to use .delay(), and when is it better to use .setTimeout()?

I think what you posted explains itself really.
Use .delay() for jQuery effects including animations.
setTimeout() is best used for everything else. For example when you need to trigger an event at a certain elapsed time.

As far as I understand, .delay() is meant specifically for adding a delay between methods in a given jQuery queue. For example, if you wanted to fade an image into view during the span of 1 second, have it visible for 5 seconds, and then spend another second to fade it out of view again, you could do the following:
$('#image').fadeIn(1000).delay(5000).fadeOut(1000);
In this instance, .delay() is more intuitive to use since it is specifically meant for delaying events in a given jQuery queue. setImeout(), on the other hand, is a native JavaScript method that isn't intended explicitly for a queue line. If you wanted an alert box to pop up 1 second after clicking on a button, you could do the following:
function delayAlert() {
var x = setTimeout("alert('5 seconds later!')", 5000);
}
<input type="submit" value="Delay!" onclick="delayAlert();" />

You can use delay with animations, for example:
$('.message').delay(5000).fadeOut();
You can also use timeOut to delay the start of animations, for example:
window.setTimeout(function(){
$('.message').fadeOut();
}, 5000);
As you see, it's easier to use delay than setTimeout with animations.
You can delay pretty much anything with setTimeout, but you can only delay animations with delay. Methods that aren't animations are not affected by delay, so this would not wait a while before hiding the element, it would hide it immediately:
$('.message').delay(5000).hide();

.delay() is mostly used for chaining together animation effects with pauses in between.
As the docs mention, there is no way to cancel the delay. In the case where you may want to cancel the delay, a setTimeout() should be used instead so you can cancel it with clearTimeout()

Another side effect of delay(): it seems to disable the ability to hide (or fadeOut, etc) the objecting being delayed, until the delay is over.
For example, I set up the following code (perhaps a stackoverflow developer will recognize the css names....) to hide a 'div':
$j(document).ready(function(){
var $messageDiv = $j("<div>").addClass('fading_message')
.text("my alert message here").hide();
var $closeSpan = $j("<span>").addClass('notify_close').text("x");
$closeSpan.click(function() {$j(this).parent().slideUp(400);});
$messageDiv.append($closeSpan);
$j('.content_wrapper_div').prepend($messageDiv);
$messageDiv.fadeTo(500, .9).delay(5000).fadeTo(800,0);
});
Clicking the "x" that's in the span (that's in the 'div') did fire off the click function (I tested with an alert in there), but the div didn't slideUp as directed. However, If I replace the last line with this:
$messageDiv.fadeTo(500, .9);
..then it did work - when I clicked the "x", the surrounding div slideUp and and away. It seems as if the background running of the "delay()" function on the $messageDiv "locked" that object, so that a separate mechanism trying to close it couldn't do so until the delay was done.

Related

jQuery delay between each toggleclass

I have made a (rather complicated) solution where I have 4 menu items pop in/out from the side and I make that happen by toggling a class.
$('.menuitem').toggleClass('show');
It works great but the client now wants it to "slide out". I figured that I can make him happy if I can create a delay between each toggle, but I cant find a good way to do it. In practice I want each menu item to toggleClass but with a delay of maybe 250ms before next toggleClass.
Edited - Apparently the delay function wont work with toggle, only with animations.
Consider this following code:
$('.menuitem').each(function(i) {
var elm=$(this);
setTimeout(function() {
elm.toggleClass('show');
}, i * 250);
});
See it in action, in this demo i have hiding diving one by one and delay is 1000 ms.
What about:
$('.menuitem').toggleClass('show').delay(1000).toggleClass('hide');
See jQuery's delay() function for further reference.
I would do the $('.menuitem').toggleClass('show') in a separate event.
For instance <button onmousedown="$('.menuitem').toggleClass('show');" onclick="myfunc();">Fast Toggle</button>
If you toggle onmousedown the page will render with the toggle before the click event fires.

Chain jQuery .addClass and .removeClass multiple times with delays

I'm working with animate.css from https://github.com/daneden/animate.css and it provides just much better animations than jQuery does. I would like to chain animations and element changes with delays to fade an element in and out and change it's contents.
The .queue method works for a single delay, but I need an efficient way to chain many .addClass, .removeClass and .html methods with a delay and the least possible syntax.
Does anybody know how to do this?
Here's an example (doesn't work, but that's what it should be):
$('div.text').delay(2000).addClass('animated fadeOutLeft').html('New content!').delay(2000).addClass('animated fadeInRight');
And that repeated many times with different content.
.delay() works with only those method with uses the queue() based execution like .animate(), so it doesn't work with .addClass() or .html().
You can use a manual queue to fix it like
$('div.text').delay(2000).queue(function () {
$(this).addClass('animated fadeOutLeft').html('New content!').delay(2000).queue(function () {
$(this).addClass('animated fadeInRight')
}).dequeue()
});
Demo: Fiddle

jQuery show hide delay still running after mouse is away

I set .delay() to stop showing on every mouse over the effect but now it is showing on every mouse over just delayed.
Seems .delay() is not the correct way to recognize the mouse over for a minimum time to show after the section.
$(document).ready(function(){
$('.article_wrapper').hover(
function(){
$(this).find('.actions').delay(800).show(300);
},
function(){
$(this).find('.actions').hide(200);
});
});
Which other Functions can I use?
On jQuery 1.9+, you can use finish() to clear all previous delay applied to specific queue:
(although this is still undocumented)
DEMO
UPDATE: indeed, to not break hide animation, you should use clearQueue()
$(document).ready(function(){
$('.article_wrapper').hover(
function(){
$(this).find('.actions').delay(800).show(300);
},
function(){
$(this).find('.actions').clearQueue().hide(200);
});
});
This is unfortunately a slightly annoying issue. The correct way of solving this is with "setTimeout", explained in greater detail here. Trying to add delay to jQuery AJAX request
This can easily be modified for your needs.
Edit
As the better answer pointed out, this isn't neccessary for animations, I'll leave it here because it is relevant to most non-animation delays.

Run a line of jQuery after the previous one is complete

I have two lines of jQuery and I need one to run after the previous one is complete.
I know js is read line by line, but the second line is happening too soon.
I can't use jQuery callbacks because these functions unfortunately don't have them.
I tried doing a setTimeout() with a wait for 500ms, 1000ms, and 1600ms, but it didn't seem to work. Visually, the second line took place before the first line was completed.
The element used in the first selector has a css transition of 1s and I want that to finish and then the second line to take place.
Is it possible to do something like:
if transition complete, run js
else wait, then check if transition complete, then if true run js.
Here are the two lines of js:
$('#searchInput').removeClass('slideBack').css('top', 0);
$('#headerTopBar').css('position', 'relative').hide();
If you want to wait for a CSS transition to complete, then you need to use an eventListener for the CSS transitionend event on the object that is doing the transition. That will then provide an event handler callback where you can carry out the second line of code after the CSS transition completes.
$('#searchInput').one("transitionend", function(e) {
$('#headerTopBar').css('position', 'relative').hide();
}).removeClass('slideBack').css('top', 0);
Now, in the real world, not every browser uses the same event name for the transition end event so one typically either installs event handlers for all the possible names of the transition end event or one in your code figure out which name is used in this local browser and then use that variable as the event name.
Note: I use .one() so that this event handler will automatically uninstall itself after it fires. I don't know for sure you want that, but it is often desirable with these types of event notifications.
Here's a more verbose version that listens for all possible transition end event names (for all major browsers):
$('#searchInput').one("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(e) {
$('#headerTopBar').css('position', 'relative').hide();
}).removeClass('slideBack').css('top', 0);
.css() does not take a callback, you can use .animate() instead:
$('#searchInput').removeClass('slideBack').animate({top:0},500,function () {
$('#headerTopBar').css('position', 'relative').hide();
});

Is setInterval() and setTimeout() bad things to do in modern jQuery animations?

I had some problems with animations with jQuery 1.6. I solved it with jQuery 1.5.
In my project I used setInterval() to make custom logo slider. Animations fired up instantly (not simultaneously) two by two. Everything goes smoothly when I am on the page, but when I went on other tab and comeback (after minute, two or so) to my page project everything goes crazy...
Ok, so I got one answer to use Queue(). Can I achieve same thing with that method?
I have book Manning jQuery in Action and there is nothing on instantly fired up animations with Queue().
Link to Jsfiddle
To quote some of that answer:
Because of the nature of requestAnimationFrame(), you should never queue animations using a setInterval or setTimeout loop.
In general setInterval == BAD and setTimeout == GOOD for animations.
setInterval will try play catchup, as nnnnnn stated:
some browsers may queue everything and then try to catch up when your
tab gets focus again
You best method for looping animate() is by calling recursively, for example:
var myTimeout;
var myAnimation = function () {
$('#myID').animate({
[propertyKey]:[propertyValue]
}, 5000, function() {
myTimeout = setTimeOut(myAnimation, 1000);
});
}
Notice how the myTimeout is held outside the scope of myAnnimation allowing the ability to stop the animation
clearTimeout(myTimeout);
Which you could hook up to the window.unload event.

Categories

Resources