jQuery's after method not working with newly created elements
Asked Answered
H

4

14

Insofar as I can tell, the following code should work, creating a <div> element, and then creating a <p> element; the expression should result in a jQuery object with two elements:

$("<div>first element's content</div>").after("<p>second element's content</p>");

However, what I get is very different. The documentation (see the heading "Inserting Disconnected DOM Nodes") tells me the above code should result in a jQuery object, grabbing both HTML snippets and building the two DOM elements. But, what I've gotten, in several different versions of jQuery, all above 1.4, is a jQuery object with only 1 node. However, the following code works just fine, returning (what I believe is) the correct jQuery object, two elements inside:

$("<div></div>").after("<p>second element's content</p>");

And this example works as well:

$("<div></div>").after("<p>second element's content</p>").after("<p>third element's content</p>");

It seems the .after() method works fine if the first DOM node being created is empty, but does not when it is not (irrespective of the contents of subsequent DOM nodes being appended to it).

Am I missing something about jQuery's internals, quirky DOM issues and/or JavaScript peculiarities, or is this simply a jQuery bug that's persisted from version 1.4 on through 1.7?

(Here's a meager JSFiddle demonstrating the issue pretty plainly.)

Hypostatize answered 7/5, 2012 at 21:21 Comment(1)
As mentioned below in the comments to elclanrs answer, add is a viable substitute, and I've whipped up a new JSFiddle to demonstrate that it works. However, this doesn't explain why the behavior displayed on the docs (and even its comments, see the whole thread containing the answers from "MarkAndrewSlade") isn't available for the after method of jQuery objects of a newly created element when that element has content.Hypostatize
P
10

This was a known bug in jQuery < 1.9. See http://bugs.jquery.com/ticket/8759

In jQuery >= 1.9, the following information from the upgrade guide should be noted:

Prior to 1.9, .after(), .before(), and .replaceWith() would attempt to add or change nodes in the current jQuery set if the first node in the set was not connected to a document, and in those cases return a new jQuery set rather than the original set. This created several inconsistencies and outright bugs--the method might or might not return a new result depending on its arguments! As of 1.9, these methods always return the original unmodified set and attempting to use .after(), .before(), or .replaceWith() on a node without a parent has no effect--that is, neither the set or the nodes it contains are changed.

Phosgene answered 7/5, 2012 at 22:33 Comment(3)
Strangely, I'm getting this same bug after updating jQuery from 1.8.2 to 1.11.0. The $.after() and $.before() methods aren't working on newly created elements. I need to firstly add the newly created element to DOM, and then insert the new content to it. Another workaround is using $.add() method, but it won't work if you wish to insert content before the element.Proficient
I also get this behavior after updating to jQuery 1.10Wardlaw
I'm using version 2.2.3 and it still does not work. Finally checked SO after banging my head against the wall.Jobbery
I
6

Use add() to add objects to the collection. I use after() more in DOM elements that already exist or that are cached in a variable, but most of the time, if you work with dynamic markup is more practical to use the equivalent insertAfter().

$("<div>first element's content</div>").add("<p>second element's content</p>");

EDIT:

This works...

var $el = $('<div/>', {
    text: 'hey there'
}).after('<p>Lorem</p>');
Insurable answered 7/5, 2012 at 21:32 Comment(2)
Thank you, elclanrs, for your reply. I will use add in the future. And I just whipped up a new JSFiddle to demonstrate that add does do what you mentioned. But this doesn't answer my question, which is why after does not.Hypostatize
Thanks again. As it doesn't answer my question, I haven't given you answer credit, but I've up-voted your answer to give the respect due it for finding a new piece of granularity in my question.Hypostatize
T
1

In jQuery 1.12.4, I found out that using a class selector instead of an ID selector solves this issue.

If you are struggling with
    $("#myelement1").after("<p>test</p>"),

add a unique class to your element and try this:
    $(".myelement1").after("<p>test</p>")

Ta answered 18/5, 2018 at 12:54 Comment(0)
C
0

I found I was still sometimes having issues with .add() in place of .after(), so another easy way to get around this bug is to make a throw away wrapper element, .append() the sibling elements, and use .html() to just get the inner contents of the wrapper.

Example:

$('body').append(
    $('<span/>').append(
        $("<div>first element's content</div>")
    ).append(
        $("<p>second element's content</p>")
    ).html()
);

This will add the <div> and <p> but discard the outer <span>. I have found this usually works fine with .append() but can have problems with .appendTo()

Censure answered 6/11, 2015 at 20:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.