why can't I delay addClass and removeClass using jquery? - javascript

This is my code:
$("#form_editor").addClass('abcd')
$("#form_editor").delay(32000).removeClass('abcd')
The class never gets applied if I have the second line uncommented. If I comment it out, then the class gets applied as expected. It seems that the second line executes without any delay at all i.e. ignores .delay(32000).
Does delay work with addClass and removeClass? I assumed it would delay the call to any function that came after it, but apparently not as it seems to execute right away.

You can, but you need to queue()
$("#form_editor").addClass('abcd').delay(3200).queue(function() {
$(this).removeClass('abcd');
});
.abcd:before{
content:"abcd";
background:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="form_editor">efgh....</div>
or use setTimeout method:
var $formEditor = $("#form_editor"); // we plan to reuse it so let's cache it!
$formEditor.addClass('abcd'); // add
setTimeout(function(){
$formEditor.removeClass('abcd'); // remove
}, 3200);
.abcd:before{
content:"abcd";
background:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="form_editor">efgh....</div>
jQuery animations (.animate, .fadeTo, fadeIn, etc...) add to the animation queue stack, an jQuery internal function than handles "what's next?" (laically speaking), while other "animation-less" methods (like .text(), addClass(), .on(), .click() etc...) do not.
To easily remember .queue() think of it as the missing (really is) callback functionality for .delay(2000, function(){ /*BAM!*/ }) /* well sadly, this does not works */

Related

What is the "right" way to work with addClass/delay/removeClass?

I have a simple task, when I click on a link, I want to add bg-success class into its child, delay 800ms then remove that class.
I can trigger addClass() after click on a link, like this, it works:
$('a').on('click', function() {
$(this).find('span.code').addClass('bg-success');
});
I can also trigger removeClass after click too, it works (alone) too:
$('a').on('click', function() {
$(this).find('span.code').removeClass('test-class');
});
I can make it delay, after addClass, let fadeOut, it works:
$('a').on('click', function() {
$(this).find('span.code').addClass('bg-success').delay(800).fadeOut(400);
});
But when I want to addClass, delay, then removeClass, it does not work, it remains the same and does nothing. I even tried with long time like 8000ms but still can't make it works. If I replaced it with 2 addClass(), it adds 2 classes at the same time, and does not care about delay():
$('a').on('click', function() {
$(this).find('span.code').addClass('bg-success').delay(8000).removeClass('bg-success');
});
I have tested with everything I can find on Stackoverflow. The weird part is, it does delay when I work with fadeIn, fadeOut and everything else. The delay() just be ignored when work with addClass/removeClass at the same time.
Anyone have issue like this, please suggest some ideas. Thank you.
Update:
Read comments and you guys will see the answer is here.
Btw, can anyone with deep knowledge about jQuery explain for me, why they decided to do that? I mean I see it is easy to make this way, addClass then delay then removeClass, what is the real reason makes the jQuery development team decided to make it won't work this way?
I would like to know because if I have the reason, I won't step into the trap like this again.
If you want to use .delay() then you need to use .queue() to specify the queue of functions that will be executed on the element after the delay.
Your code should be:
$('a').on('click', function() {
$(this).find('span.code').addClass('bg-success').delay(800).queue(function() {
$(this).removeClass('bg-success');
$(this).dequeue();
});
});
This is a DEMO snippet:
$('a').on('click', function() {
$(this).addClass('bg-success').delay(800).queue(function() {
$(this).removeClass('bg-success');
$(this).dequeue();
});
});
a {
width: 100px;
height: 100px;
background-color: blue;
cursor: pointer;
}
.bg-success {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a>A link</a>
But you can also simulate this effect with setTiemout():
$('a').on('click', function() {
var myLink = $(this).find('span.code');
myLink.addClass('bg-success');
setTimeout(function() {
myLink.removeClass('bg-success');
}, 800);
});
delay() limitations:
To get further details why delay() is better used with effects only, you can see in the jquery documentation that unfortunately, it has some limitations over the native JavaScript setTimeout function:
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.
From the docs:
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.
(https://api.jquery.com/delay/)
I'd suggest using setTimeout like so:
$('a').on('click', function() {
var span = $(this).find('span.code');
span.addClass('bg-success');
setTimeout(function() {
span.removeClass('bg-success');
}, 800);
});
You can always try with plain old JS with setTimeout() function, to wait for certain period of time before doing something else:
$('a').on('click', function() {
var myCode = $(this).find('span.code').addClass('bg-success');
setTimeout(function(){
myCode.removeClass('bg-success');
}, 800);
});

How to detect when all animations have stopped?

I'm using this code to stop simultaneous animations on 2 elements:
$('#container').find('*').stop(true, true);
The animation can be stopped by an end user hovering over a button, in which case the animation stops after completion (which is what I want). However, the button hover also initiates another function (removes and reloads the elements), and there's a conflict if that function runs before the animations are complete.
I was thinking that using 'after' or 'complete' with the above code might work, but I can't figure out what the syntax would be.
im not sure what you are trying to achieve, but in order to check whether or not there are running/pending animations on the object using jQuery, you can use .promise().done()
example, somehing of this sort:
var animations_running;
$('#container').promise().done(function() {
animations_running=false;
});
$('#container').on("mouseover",".SomethingInside",function(){
if(animations_running==false){
//...do animations...
animations_running=true;
}
});
you can also add a callback function to your jQuery animations as follows:
$('#container').on("mouseover",".SomethingInside",function(){
if(animations_running==false){
$(this).animate({
left:+=50
},500,function(){
//...this is the callback function...
});
animations_running=true;
}
});

Callback function to be executed after jQuery show / hide?

In iOS, the following code has a noticeable flicker between the hide() and the scrollBy():
element.hide();
window.scrollBy(0, -elementHeight);
This is because toggling between display: none and display: block on iOS is a heavy task, as if the elements are being added to and removed from the DOM.
I need a way to perform window.scrollBy() as a callback, once the hide() has successfully completed and the DOM has updated. Is there a way to do this in jQuery?
Either pass a duration and a callback, or just pass a callback option, like this:
element.hide(0, some_function);
// or
element.hide({done: some_function});
By default, the second option takes 400 ms. To do it immediately, use one of these:
element.hide(0, some_function);
// or
element.hide({duration: 0, done: some_function});
Here's a jsFiddle demo.
See the jQuery documentation for more details.
From the jQuery api:
.hide(options)
complete
Type: Function()
A function to call once the animation is complete.
Try this:
element.hide({complete: function(){
window.scrollBy(0, -elementHeight); });

Jquery $('#div').show().delay(5000).hide(); doesn't work

I'm trying to show a div thats set to display: none; for 5 seconds with
$('#div').show().delay(5000).hide();
but it deson't work, it just goes straight to hide()
Can any of you help me?
Do it like this:
$('#div').show(0).delay(5000).hide(0);
By passing in numbers to .show() and .hide(), jQuery will take those methods into its internal fx queue (even if the number is zero). Since .delay() only works within a queue, you need that little workaround.
example: http://jsfiddle.net/zceKN/
You need to use .queue() because .hide() isn't queued by default.
$("#div").show().delay(5000).queue(function (next) {
$(this).hide();
next();
});
You need a duration on your hide for it to work:
$('#div').show('slow').delay(5000).hide('slow');
Example: http://jsfiddle.net/Paulpro/GLTaB/
$('#div').show();
setTimeout(function(){$('#div').hide();}, 5000);
.delay() works for animations only

Ordering events in jquery

I have a construct like this.......
<div id="right_top_block" class="drop_head">
<div id="right_top_block_head" class="dropper block_head rounded-corner">
Friends
</div>
<div class="box_container">
<div id="box_list" class="drop_list">
<ul id="right_top_ul">
</ul>
</div>
</div>
</div>
I removed the inner contents as it is too lengthy... and i have a jquery like this...
$(document).ready(function() {
$('.drop_head').each(function(i, e) {
$('.dropper', e).click(function() {
$('.drop_list', e).slideToggle(1500);
});
});
$('.dropper').click(function(e) {
$(e.target).parent().removeClass('leaf_class');
if ($(e.target).parent().height() < 300) $(e.target).parent().addClass('leaf_class');
});
});
Now what happens is, each time the dropper is clicked, a leaf class is added to the right_top_block and then a slideDown(as part of slideToggle) on the correspoding drop_list is done( I have many such).... Now if it is clicked again the leaf class is removed from the right_top_block and then a slideUP(as part of slideToggle) on the corresponding drop_list is performed. But what i really want is, when a slideUp is performed, i want the slideToggle to complete and then i want the leaf_class to be removed. How do i change the order of the event execution? I guess due to the delay 1500 i am specifying in the toggle is the cause for this. While don't want to loose the slow transition that it gives, i want that to be completed and then the leaf class to be removed. How do i do this?
First, two remarks about the code in your question:
The code that runs on click is split into two event handlers: one responsible for the slide animation and the other for the class change. That's quite confusing and actually makes the problem more complex. It would be easier if these two handlers were merged into one, or if one handler was performing the whole slideDown() operation sequence and the other the whole slideUp() sequence.
You're using e.target with an element that doesn't seem to contain any descendant from where a click event would bubble up. That's perfectly valid in itself, but using this instead would be shorter and make your intent clearer.
Now, let's look at your requirements. It looks like you want leaf_class to be added before the slideDown() animation starts, but only removed after the slideUp() animation completes.
You can achieve that in a simpler way with a pair of handlers bound to the toggle event, and explicit calls to slideDown() and slideUp() instead of slideToggle().
$('.dropper').toggle(function() {
var $dropHead = $(this).parent();
$dropHead.addClass("leaf_class");
$(".drop_list", $dropHead).slideDown(1500);
}, function() {
var $dropHead = $(this).parent();
$(".drop_list", $dropHead).slideUp(1500, function() {
$dropHead.removeClass("leaf_class");
});
});
If I've understood what you're asking, then you're looking for a callback function to your slideToggle function:
$('.drop_list', e).slideToggle(1500, function() {
//Do stuff after slide is complete
});
The callback function is executed upon completion of the slide animation. See the jQuery docs for more information.

Categories