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

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);
});

Related

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

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 */

jQuery How to make a popup Appears / Disappears on timer?

When my website loads, the popup appears - I need to make it automatically close after a specific time.
$(document).ready(function () {
//select the POPUP FRAME and show it
$("#popup").hide().fadeIn(1000);
//close the POPUP if the button with id="close" is clicked
$("#close").on("click", function (e) {
e.preventDefault();
$("#popup").fadeOut(1000);
});
});
There is already a button but i need to remove it.
You can use the delay() function for that:
$(document).ready(function() {
$("#popup").hide().fadeIn(1000).delay(5000).fadeOut(1000);
$("#close").on("click", function(e) {
e.preventDefault();
$("#popup").fadeOut(1000);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="popup">popup</div>
Please mind the note that is given on the documentation:
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.
Javascript have option setTimeout .setTimeout is a native JavaScript function (although it can be used with a library such as jQuery, as we’ll see later on), which calls a function or executes a code snippet after a specified delay (in milliseconds).
setTimeout(function() {
$("#popup").fadeOut(1000);
}, 1000);
or in jquery use .delay(). Set a timer to delay execution of subsequent items in the queue.
$("#popup").delay(1000).fadeOut(1000);

Is it possible to bind a handler to a jQuery effect?

I would like to call function when slideUp or slideDown are performed on an element. Is this possible?
Something like:
$('#panel').on('slideUp', function() { open--; });
$('#panel').on('slideDown', function() { open++; });
Update: The problem is that there are a ton of slide calls (e.g.: $().slideUp()) all over the page, within ajax responses, hash link clicks, etc.. I was hoping to bind to the slide itself somehow rather than add code to each calling function.
You cannot bind to an event since there is no such.
But you can pass a handler that will be called after animation is finished
$('#panel').slideUp(function() { ... });
http://api.jquery.com/slideUp/
If you really want to do this, you can use custom events and your own little plugin, something like this:
$.fn.mySlideToggle = function() {
this.slideToggle();
this.trigger('mySlideToggle');
}
$('div').on('mySlideToggle', function(){ console.log('hey') });
$('button').on('click', function(){ $('div').mySlideToggle(); });
Here's a little demo (check console): http://jsbin.com/asejif/2/edit
In your case it is redundant though, since you can use the callback that the slide events provide, but it might be useful for other things...

Problems with removing elements in jQuery

I am attempting to remove an object from a page with jQuery. I also want to animate the removal. The goal is to make the element fadeOut(), wait a second, then remove(). But it seems to refuse to wait to remove the element, even when I use it in a setTimeout() function. How can I make an element fadeOut(), and then remove() it?
$("button").click(function() {
$(this).fadeOut();
setTimeout(function() { $(this).remove();}, 1000);
});
Read manual carefully:
http://api.jquery.com/fadeOut/
The fadeOut() method has a callback that is invoked after the fadeOut completes. To use it:
$("button").click(function() {
$(this).fadeOut(function() { $(this).remove();});
});
There should be no reason to wait one second after the fadeOut completes, before removing the element, because the element will be invisible when it is removed.
In your timeout function, this isn't what you think it is - it's actually the global window object.
In any event (no pun intended) you should use a "completion callback":
$("button").click(function() {
$(this).fadeOut('slow', function() {
$(this).remove();
});
});
Never, ever, mix setTimeout and the animation queue. It's fine to interleave the two, i.e having a completion callback start a timer, or having a timer starting an animation, but it's never OK to assume that you can start both a 1000ms animation and a 1000ms timer and have them complete at the same time.
EDIT fixed code - no need for self in a completion callback, I was still thinking about setTimeout and this when I wrote that!
$('button').click(function(){
$(this).fadeOut(function(){$(this).remove()});
});​
DEMO
Why not just use the callback of fadeout?
$("button").click(function() {
$(this).fadeOut(function(){$(this).remove();});
});
try this one, maybe it helps:
$("button").click(function() {
(function(that) {
that.fadeOut();
setTimeout(function() {
that.remove();
}, 1000);
})($(this));
});

jQuery effects combination

I want to apply highlight and remove effects to the same dom. One after the other. Unfortunately the highlight effect is not visible as the remove gets triggered immediately after.
Any idea to delay the remove action?
$("#<%= dom_id(#stock) %>").effect("highlight", {}, 4000)
$("#<%= dom_id(#stock) %>").remove()
Problem is, .remove() can't be delayed. It is one of those functions that triggers right away, meaning .delay() does nothing.
However, JavaScript's setTimeout() function will:
$('#g').click(function(){
$("#hi").hide("highlight", {}, 4000)
setTimeout('$("#<%= dom_id(#stock) %>").remove();', 4100)
});
Here's an example of this on jsFiddle.
.effect() have callback argument that will get called after effect finishes. See effect demo.
$("#<%= dom_id(#stock) %>").effect("highlight", {}, 4000, function() {
$("#<%= dom_id(#stock) %>").remove();
});
Is effect a jQuery PlugIn ? I cant find any documentation of that function on the jQuery Site.
Use jQuery Animate because you got a callback after your animation is done.
$("#<%= dom_id(#stock) %>").animate({
opacity: 0.25,
}, 4000, function() {
// Animation complete.
$("#<%= dom_id(#stock) %>").remove();
});
Update
like Shawn31313 said
effect(..)
is part of jQuery UI and this function also supports "callbacks" after the effect is done.
jQuery UI Effect
hope this helps

Categories