jQuery show() fail with last(), after() and "blind" effect
Asked Answered
B

2

6

I'm getting a bug from jQuery 1.10.2, the last one, and I would know if anybody have any (other) solution for this issue.

My script create multiple DIV blocks (named items) from one model (item model), add the current after the last one and display it with a "blind" effect.

Here is the code but you can also test it online at this link.

<div id="item_model" style="display: none;" class="item">MODEL</div>
<button class="addBtn">Add 5 items</button>

<script>
$(".addBtn").click(function() {
    for( var i=0; i<5; i++ ) {
        // Clone model
        var p = $("#item_model").clone(true, true);

        // Modify item
        p.removeAttr("id");
        p.text("ITEM n°"+(i+1));

        // Add item to the DOM
        $(".item").last().after(p);

        // Show item
        $(p).show("blind");
        //$(p).show();
    }
});
</script>

The issue is the same with :last and insertAfter().

The logic:

  • First item is well displayed and its effect occurred (or not, another bug ? but the time elapses)
  • During an effect animation, the element is outsourced ou replaced.
  • The next items are inserted out of the DOM (event if after() should insert it in the DOM), so there are not in the page.

This behavior is an error from jQuery but I have to overcome this problem.

The solutions i know:

  • Don't use any effect.
  • Use a container and append().
  • Use slow effect instead of blind. (Thanks to A. Wolff)
  • Add elements to the DOM and AFTER, show all. (Thanks to A. Wolff)

Thanks to all for your contribution.

Blus answered 23/9, 2013 at 8:26 Comment(4)
Bizarrely, if I put your code in a JSFiddle it works fine: jsfiddle.net/TrueBlueAussie/n2UVpBurnout
@TrueBlueAussie not if you have jQuery UI jsfiddle.net/arunpjohny/AN3ft/1Gap
@Arun P Johny: Well spotted. So the problem is with the inclusion of JQueryUI. At least that narrows it down :)Burnout
problem seems to be the effect: jsfiddle.net/AN3ft/2Oberland
O
1

This snippet fixes it:

$(".addBtn").click(function () {
    var p = $("#item_model").clone(true),
        tmp = $();
    p.removeAttr("id");
    for (var i = 0; i < 5; i++) {
        tmp = tmp.add(p.clone(true).text("ITEM n°" + (i + 1)));
    }
    $(".item").last().after(tmp);
    tmp.show("blind");
});

DEMO

Oberland answered 23/9, 2013 at 8:54 Comment(1)
@TrueBlueAussie I suppose this is due on how jquery UI handles animation. This will need more investigation to debug it. Here i animate all elements at once, not each individually. Anyway, animating set of elements is still better than animate all elements of a setOberland
D
1

I found a rational (if intricate) explanation for your bug.

The root cause : you are using a jquery-ui effect (not a basic jquery effect), and you add elements after last inserted item, before the animation has finished.
The gotcha : jquery-ui uses wrappers during its animations, and if a wrapper is already present, it reuses it.

Here is the detailed walkthrough :

  • When animating the first item : for the duration of the effect, the item is wrapped in a div with class ui-effects-wrapper, and this wrapper div is animated to give the blind effect
  • When adding the second item : adding it after "last" (<- in this case : the first item) actually adds it inside the wrapper.
  • When animating the second item: jquery-ui reuses the existing wrapper (shortcut in createWrapper, see below)
  • Same goes for items 3-5
  • When first animation ends, the wrapper element is removed and replaced whith the first animated elements. The other elements (remember : they were attached as children of this wrapper) end up dangling with no parent.

Relevant pieces of code :
jquery-ui code : snippet 1 - blind() function
jquery-ui code : snippet 2 - createWrapper() inner function
jquery-ui code : snippet 3 - blind() code when animation completes

I don't think this should be considered as a jquery-ui bug - your use case is, IMHO, pretty isolate, and I wouldn't imagine what "correcting" this would trigger elsewhere.

Solutions :

  • slideDown will work (fiddle - it animates the element, no wrapper there)
  • add a <span id="beacon"></span> item and insert new elements before #beacon
  • A. Wolff's solution
  • as you already found out, .append() on a common container
Delineator answered 10/10, 2013 at 14:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.