Execute complete function only once in jQuery animation? - javascript

I'm trying to animate the font size of some text:
$("p").delay(500).animate({
"font-size": "+=50"
}, 1000, function() {
alert("Done");
})​;
Here's a demo.
I want to do something after animating the <p>s, which in the example is alert, but it surprisingly runs it for each <p>, and that's not what I want. Is there a possible way to make it just run once or is it not possible?

Just to notice, you can also use a promise object:
Return a Promise object to observe when all actions of a certain type
bound to the collection, queued or not, have finished.
First example (demo):
$("p").delay(500).animate({
"font-size": "+=50"
}, 1000).promise().done(function(){
alert("done");
});​
Second example (demo):
$.when($("p").delay(500).animate({
"font-size": "+=50"
}, 1000)).done(function(){
alert("done");
});​

var $p = $("p");
var lastIndex = $p.length - 1;
$p.delay(500).animate({
"font-size": "+=50"
}, 1000, function() {
if ($p.index($(this)) == lastIndex) {
alert("Done");
}
})
Demo

You could just keep a flag, since they should animate simultaneously:
var done = false;
$("p").delay(500).animate({
"font-size": "+=50"
}, 1000, function() {
if(!done) {
done = true;
alert("Done");
}
})​;
Here's a demo.

Give the P-tag in question an ID and select that ID rather than every P tag on the page. Like here: http://jsfiddle.net/LR8uP/1/
Or if you want to animate every P-tag but run the function only once, add a state variable, like here: http://jsfiddle.net/LR8uP/2/

This code can be used as a generic 'countdown' type of function.
// Function that returns a function,
// which when invoked 'count' number of times,
// will invoke the function 'fn'
function runOnZero (count, fn) {
return function () {
if (--count <= 0) {
fn();
}
};
}
// Get all the <p>s
var ps = $("p");
// Do your thing after ps.length calls
var whenAllDone = runOnZero(ps.length, function () {
alert("Done");
});
ps.delay(500).animate({
"font-size": "+=50"
}, 1000, whenAllDone)​;

Related

Set delay for the second click function jQuery

I want the second click function to be delayed by 500ms, where do I insert this?
$(document).ready(function(){
$('.dropToggler').click(function() {
$(this).parent().addClass("open");
});
$('.acceptCta').click(function() { //I want the delay on this function.
$(this).parent().removeClass("open");
});
});
Tried this too, didn't work:
$(document).ready(function() {
$('.dropToggler').click(function() {
$(this).parent().addClass("open");
});
setTimeout(function() {
$('.acceptCta').click(function() {
$(this).parent().removeClass("open");
});
}, 800);
});
You need to delegate and tell which element you are referring to when clicking and use that for setTimeout - removeClass function
var $this = $(this) // will be click function
setTimeout(function() {} does not know what is $(this) as we searching for the parents of the clicked event element.
$(document).ready(function() {
$('.dropToggler').click(function() {
$(this).parent().addClass("open");
});
$('.acceptCta').click(function() {
//This needed
var $this = $(this)
//delay removeClass
setTimeout(function() {
$this.parent().removeClass("open");
}, 800);
});
});
setTimeout(function(){
//your code goes here
alert("Hello");
}, 3000);//here you can set the time in milliseconds
you can use the setTimeout Function

Query animate() doesnt working

I have the following code:
var isOn = false;
$('.switch').on("click",function(){
if (isOn){
$('.toggle').animate({
left:"18px"
},10,"linear",
{
complete: function(){
$('#label').text("ON");
}
});
isOn = false;
} else {
$('.toggle').animate({
left:"4px"
}, 10,"linear",
{
complete: function(){
$('#label').text("OFF");
}
});
isOn = true;
}
});
http://codepen.io/pietrofxq/pen/LpzDE?editors=001
It is a switch on/off made with jquery. It was working without the animate() method.
I was doing the animation with css, but it was buggy in Internet Explorer.
Here is the original effect: http://codepen.io/anon/pen/iwatp
Why the complete function in the first link isn't working?
EDIT: This code is working but still doesnt work properly on IE
You seem to be mixing the two different signatures of the .animate function. If you pass the duration and the easing directly as arguments, you have to do the same for the callback function:
$('.toggle').animate({left: "18px"}, 10, "linear", function(){
$('#label').text("ON");
});
OR you have to pass two objects:
$('.toggle').animate(
{
left:"18px"
},
{
duration: 10,
easing: "linear",
complete: function(){
$('#label').text("ON");
}
}
);
now it will work. please check the jsfiddle link
http://jsfiddle.net/banded_krait/da2kE/
I removed some brackets and complete: array key from your code and hope this will work for you.

How do I "do stuff" at the end of this crazy jQuery animation loop without errors?

I am trying to "do some stuff" at the end of this crazy animation loop... The alert I have commented out at the end of the animation works great... However, what I really need it to do is remove/hide the closest div with a class of .item (something like this)
var jremove = $(this).closest('.item').hide();
$container.masonry('remove', jremove );
//Then trigger a reload function for masonry
reloadMasonry(); // not working yet
When I try do do anything but alert a simple message I get an error like this:
Uncaught TypeError: Object #<HTMLImageElement> has no method 'closest'
You can see it at the bottom of the animation below:
jQuery(function ($) {
$("body").on("click", ".clip_it", function () {
if ($(this).parent().find(".clip_it").length<1){
$(this).after('<a class="clip_it" href="javascript:void(0)" onclick="">CLIP IT!</a><img src="http://img.photobucket.com/albums/v29/wormholes201/animated-scissors.gif" class="ToBeAnimated">');
}
animationLoop($(this).closest(".item-inner").eq(0),$(this).parent().find(".ToBeAnimated").eq(0));
});
});
function animationLoop(ctx,ctx2) {
ctx2.fadeIn();
ctx2.css({
top: (0 - parseInt(ctx2.height()) / 2),
left: (0 - parseInt(ctx2.width()) / 2),
position:"absolute",
"z-index":800
}).rotate(270);
ctx2.animate({
top: ctx.height() - ctx2.height() / 2
}, 1000, function () {
ctx2.animate({
rotate: "180deg"
}, 1000, function () {
ctx2.animate({
left: ctx.width() - ctx2.width() / 2
}, 1000, function () {
ctx2.animate({
rotate: "90deg"
}, function () {
ctx2.animate({
top: 0-ctx2.height() / 2
}, 1000, function () {
ctx2.animate({
rotate: "0deg"
}, function () {
ctx2.animate({
left: (0 - parseInt(ctx2.width()) / 2)
}, 1000, function () {
setTimeout(animationLoop(ctx,ctx2), 1000);
//I want to remove the coupon (.item) & reload masonry here
// TEST ALERT WORKS = alert("animation complete");
var jremove = $(this).closest('.item').hide();
$container.masonry('remove', jremove );
reloadMasonry();
return false;
});
});
});
});
});
});
});
}
I am open to other suggestions if you think there is a better way? THANKS FOR HELPING!
Uncaught TypeError: Object #<HTMLImageElement> has no method 'closest'
The problem is that $ outside of your ready handler (the function you're passing into jQuery(function($) { ... });) is not pointing to jQuery, it's pointing to something else (my guess would be Prototype or MooTools). So $(this) returns an HTMLImageElement (probably enhanced by Prototype or MooTools) rather than a jQuery object, and so it has no closest function.
Either move the animationLoop function into your ready handler (so it sees the $ that jQuery passes into the ready handler instead of the global), or use jQuery instead of $ in that function.

finish animation before starting another

Problem: Whenever I click faster or slower I need last .click() call to finish before the next one starts. If you click the button faster , in the given example, you can see it's leaving divisions with 0 opacity.
What I want to achieve is stacking up till 3-4. I tried some queue code examples, couldn't make it work.
$("#addNew").click(function(){
var _this = $("#scrollable");
//Switch classes
_this.find("div.first").switchClass("first","second",500);
_this.find("div.second").switchClass("second","third",500);
_this.find("div.third").switchClass("third","fourth",500);
_this.find("div.fourth").switchClass("fourth","fifth",500);
// Insert first/new line
$("<div class='first'>Hello!</div>").css("opacity","0").hide().prependTo(_this).slideDown(function(){$(this).stop().animate({opacity:1},300)})
$("div.fifth").fadeOut().remove();
});
Here is example: http://jsfiddle.net/gtFyP/5/
Use setInterval
You could combine the below flag solution with setInterval, and thus be able to process clicks occurring during an animation.
Updated your JS Fiddle again with this alternate solution.
$(function() {
var clicking = false;
var clickCache = 0;
window.setInterval(function(){
if (!clicking && clickCache) {
processClick();
clickCache--;
}
}, 100);
var processClick = function() {
var _this = $("#scrollable");
//Switch classes
_this.find("div.first").switchClass("first", "second", 500);
_this.find("div.second").switchClass("second", "third", 500);
_this.find("div.third").switchClass("third", "fourth", 500);
_this.find("div.fourth").switchClass("fourth", "fifth", 500);
clicking = true;
// Insert first/new line
$("<div class='first'>Hello!</div>").css("opacity", "0").hide().prependTo(_this).slideDown(function() {
$(this).stop().animate({
opacity: 1
}, 300, function(){
clicking = false;
});
});
$("div.fifth").fadeOut().remove();
};
$("#addNew").click(function() {
clickCache++;
});
});
Use a Flag
You could use a flag - only start an animation if it's false. When you start animating, set it to true, when the animation is done, set it back to false.
I've modified your JS Fiddle.

How do I animate elements stored in an array? except for the one I'm hovering over?

This is what I have:
jQuery.each(shapes, function(i) {
this.hover(function(event) {
this.animate({
fill: "#fff"
}, 500);
}, function(event) {
this.animate({
fill: "#555"
}, 500);
});
});
I'm using raphael.js, but I figure this issue is general to jQuery syntax.
So, when I hover over an element (stored in shapes) I want that element to remain as-is, but then change che opacity of all the other elements. I don't know where to start.=\
EDIT:
so, I feel like, as far as semantics goes, this should work:
jQuery.each(shapes, function(i) {
current_shape = this;
this.hover(function(event) {
jQuery.each(shapes, function(j){
if (shapes[users_with_direct_employees[j][0]] != current_shape){
shapes[users_with_direct_employees[j][0]].animate({
fill: "#fff"
}, 500);
}
});
}, function(event) {
jQuery.each(shapes, function(j){
if (shapes[users_with_direct_employees[j][0]] != current_shape){
shapes[users_with_direct_employees[j][0]].animate({
fill: "#555"
}, 500);
}
});
});
});
but only the last touched shape does the animation. I'll make a js fiddel here in a bit
fiddle: http://jsfiddle.net/G5mTx/1/
Assuming, the shapes array is an array of DOM elements, I think you can use something like this where you set up a hover event handler for each shape and then within each function passed to the hover event handler, you iterate over the shapes array and if it's not the one that you are hovering over, you do the animation.
jQuery.each(shapes, function(i) {
this.hover(function(event) {
var self = this;
jQuery.each(shapes, function(index, value) {
if (value != self) {
$(value).animate({fill: "#fff"}, 500);
}
});
}, function(event) {
var self = this;
jQuery.each(shapes, function(index, value) {
if (value != self) {
$(value).animate({fill: "#555"}, 500);
}
});
});
});
or it might be cleaner with a local function:
jQuery.each(shapes, function(i) {
function animateIfNotMe(me, fillValue) {
jQuery.each(shapes, function(index, value) {
if (value != me) {
$(value).animate({fill: fillValue}, 500);
}
});
}
this.hover(function(event) {
animateIfNotMe(this, "#fff");
}, function(event) {
animateIfNotMe(this, "#555");
});
});
EDIT: I see you've added actual code now to your question (since I wrote my answer) and shapes isn't an array of DOM objects (it would be nice if you had disclosed that originally) so obviously this code won't work exactly as it is, but hopefully you can get the idea from this code for how you can iterate over all the other shapes and just exclude the current one you are hovering on and you can then adapt it to your particular shapes data structure.
You can use the method .not():
jQuery.each(shapes, function(i) {
$(this).hover(function(event) {
shapes.not($(this)).animate({

Categories

Resources