8
$("#div1, #div2").fadeIn('500',function(){
    {
        console.log('Test');
    }
});

Fiddle here: http://jsfiddle.net/y97h9/

The above code will print 'Test' two times in the console. How can I make it print only one time. Is it possible?

  • What do you except? if div2 not exists? Test or no Test in console? – Grim Apr 08 '13 at 14:54
  • put a boolean outside the check, switch it inside the check. – Shark Apr 08 '13 at 14:54
  • 5
    You've called the function on 2 different DOM elements. It's normal that the function gets called twice. What else did you expect to happen? – Darin Dimitrov Apr 08 '13 at 14:54
  • possible duplicate of [Callback of .animate() gets called twice jquery](http://stackoverflow.com/questions/8790752/callback-of-animate-gets-called-twice-jquery) (the unmarked answer is the one you're looking for) – Kevin B Apr 08 '13 at 14:54
  • The first parameter for `fadeIn` needs to be a `String` ("slow" or "fast") or a `Number` (representing the milliseconds the animation should take to complete). Passing "500" will just use the default `400` milliseconds since it's a `String`. – Ian Apr 08 '13 at 15:05
  • If you are interested going further with this try googling : JavaScript Singleton Functions – Rosmarine Popcorn Apr 08 '13 at 15:12

3 Answers3

27

Sure, you can use jQuery promise to solve multiple callbacks problem:

$("#div1, #div2").fadeIn('500').promise().done(function()
{
    console.log('Test');
});

The .promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended

Working Demo

James Donnelly
  • 126,410
  • 34
  • 208
  • 218
Eli
  • 14,779
  • 5
  • 59
  • 77
  • What happens if `#div1` or `#div2` already have animations happening in addition to the `fadeIn`? Won't it wait too long (possibly)? Maybe I'm misunderstanding – Ian Apr 08 '13 at 15:00
  • @ian It could, yes. Though i doubt that's going to happen very often, i'd consider it an edge case that would have to be dealt with when it comes along. – Kevin B Apr 08 '13 at 15:12
  • That was a beautiful answer! +1 – fernandosavio Apr 08 '13 at 15:13
  • @KevinB I don't see how it's an edge case...I would think it's fairly common/possible. The use of `promise()` here is far from a solution. Any element could have a specific animation being applied to it at any time. Using `promise()` doesn't guarantee it's specifically for the fading. Here's an example of it failing: http://jsfiddle.net/n5dB7/ – Ian Apr 08 '13 at 15:15
  • The element is hidden, and being faded in. How many hidden elements are animating normally? – Kevin B Apr 08 '13 at 15:23
  • @KevinB I don't think it matters. As my fiddle illustrates, if an animation is created for the element even after the `fadeIn` call (but not completed), it adds it to the queue. The promise waits for that queue to be done. It doesn't have to be added immediately after the `fadeIn` call, just before the time that the fading is actually done. There's plenty of time for that. And I guess my point is why use a solution that doesn't cover every case. jmar777's solution immediately and fully solves the problem. – Ian Apr 08 '13 at 16:16
  • 11
    @Ian Relax, I can understand your point. I just give OP the best way to solve the problem in his current situation. Sometime, we cannot cover every aspects that could happen in just one answer :) – Eli Apr 08 '13 at 16:30
3

The callback will run once for every matched element. You can always set a flag to see if it's been run already though:

var hasRun = false;
$("#div1, #div2").fadeIn('500', function() {
    if (hasRun) return;
    console.log('Test');
    hasRun = true;
});
jmar777
  • 38,796
  • 11
  • 66
  • 64
  • Very ugly. This is a [well-solved problem](http://api.jquery.com/promise/) in JavaScript and jQuery, and this is not the solution to use. – user229044 Apr 08 '13 at 15:08
  • @meagar I don't see how `promise` can solve this...and this answer is far from "ugly". It's spot on, actually. – Ian Apr 08 '13 at 15:19
  • 3
    @meagar It's not especially clever, but it's straight forward and won't suffer from some of the subtle issues being discussed in user1479606's answer. I do, however, prefer his answer over mine if you don't have other animations at play at the same time. Ian, thanks :) – jmar777 Apr 08 '13 at 16:19
-1

Use a boolean flag to prevent console.log('Test'); from being called twice.

var isCalled = false;
$("#div1, #div2").fadeIn('500',function(){
    if(!isCalled) {
        isCalled = true;
        console.log('Test');
    }
});