10

HTML Code

<div id="foo">
    <h1>foo</h1>
    <p>Pellentesque habitant morbi tristique.</p>
</div>
<div id="bar">
    <h1>bar</h1>
</div>

jQuery Code

$('#bar').click(function () {
    $('#foo p').hide('slow').appendTo('#bar').show('slow');
})

Expected Result

When #bar is clicked

  1. hide the p element in #foo
  2. append p to #bar
  3. show p which is now a child of #bar

Actual Result

  1. append p to #bar
  2. hide the p element in #foo
  3. show p which is now a child of #bar

Questions

  • What determines the execution order of methods in jQuery chains?
  • How can I ensure that each event completes before the next starts?
Justin Johnson
  • 30,978
  • 7
  • 65
  • 89
Beau Smith
  • 33,433
  • 13
  • 94
  • 101

7 Answers7

8

To ensure you execute something AFTER an effect like hide or show, use a callback. http://docs.jquery.com/Effects/show#speedcallback

To Add:

Vincent is right, the execution is actually

  1. start hiding the p element in #foo (SLOWLY)
  2. append p to #bar (in a snap)
  3. start showing p which is now a child of #bar (SLOWLY)

What you saw was the result of the effect

  1. append p to #bar (executed)
  2. hide the p element in #foo (COMPLETED)
  3. show p which is now a child of #bar (COMPLETED)
o.k.w
  • 25,490
  • 6
  • 66
  • 63
4

The expected result is correct. The observed behaviour may be a result of hide('slow') which runs asynchronously. So it runs while the next action executes. So it appears as if p is appended to #bar first. You can try hide() without the slow to see if that makes a difference.

Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
3

If you want to wait until each animation completes before doing the next step, use the animation callbacks detailed in the documentation:

$('#bar').click(function () {
  $('#foo p').hide('slow', function(){
    $(this).appendTo('#bar').show('slow');
  });
});
Sixten Otto
  • 14,816
  • 3
  • 48
  • 60
  • I like the idea of re-coding of the original codes to prevent the 'async' symptoms; yet maintaining a single statement. – o.k.w Oct 21 '09 at 04:51
  • 1
    This does not answer the question that was asked (it answers the question that prompted the users question). – Matt Parkins May 16 '12 at 10:23
1

Pretty sure it's executed in the order you invoke it, it probably starts the hide part and a split second later it's appended to that other element but the animation part has already begun, it takes longer than a millisecond because you set it to 'slow' and it's jumping in opacity from 1 to 0, going from say 1 to .9 to .8 in milliseconds.

$.fn.hide = function() { alert('hiding'); return this; };
$.fn.appendTo = function() { alert('appending To') }
$('body').hide().appendTo('html')
meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
1

show() and hide() are actually animation effects but when no arguments are passed they use an "instant" duration. However, due to the fact that they're implemented as animations, that means that they don't execute synchronously with the function chain. Thus, what you really should be using is a callback off of the hide() call to trigger a callback function which calls append() and then show().

http://docs.jquery.com/Effects/show

http://docs.jquery.com/Effects/hide

Amber
  • 507,862
  • 82
  • 626
  • 550
1

Hide is asynchronous. If you want to wait for it to finish, you need to put all the code you want to run after it into a callback function that you pass to hide as a parameter.

Gareth Simpson
  • 36,943
  • 12
  • 47
  • 50
0

You have to use callback if you want to queue the other methods run after the show hide thing like "Sixten Otto" has said. The animation of show hide will not wait for append method to execute. It starts a separate thread with setInterval while in the meantime, other code is invoked. So the result you got is not unexpected.

Mahbub
  • 3,108
  • 24
  • 29