jQuery.after() does not work as expected
Asked Answered
R

6

6

Please have a look at: http://jsfiddle.net/s6VdW/

HTML:

<div id="test"></div>

JS:

var span1 = $("<span/>").text("Hello");
var br = $("<br/>");
var span2 = $("<span/>").text("World!");
span1.after(br).after(span2);

$("#test").append(span1);

Expected result is:

Hello
World

Expected Result as HTML is:

<div>
    <span>Hello</span>
    <br/>
    <span>World</span>
</div>

What is the error? According to the jQuery Docs (http://api.jquery.com/after/) it should be possible:

.after() will also work on disconnected DOM nodes.

and

That set can be further manipulated, even before it is inserted in the document.

UPDATE

It seems, that I need to append the first span to the DOM first, before using .after(). But what is the alternative? If I can't access the DOM, e.g. because I'm in a DOM-unaware part of the code? http://jsfiddle.net/s6VdW/10/

UPDATE 2

I can create a "temporary" div, to which I append the elements to. Then I return the children of that div. Demo: http://jsfiddle.net/s6VdW/13/ - Does that look like the way to go?

Reeta answered 13/3, 2013 at 10:1 Comment(4)
Please don't just post the code in a fiddle. Include the code here and use the fiddle for reference/demo. We like our questions self-contained. =)Pleven
@Sandro, looks like a bug, either in the documentation or in the library. span1.after(br).after(span2).length returns 1, but it should be 3. Maybe you should open a ticket in jQuery's bug tracker.Raillery
@Reeta I think you are creating html dynamically so you need to call append() first and then make a call to after().Sunken
update2 is definitely the correct approach. an element cant have siblings if it isn't part of something that can contain children.Flavine
T
0

The problem is you create span1 dynamically at the same time you use .after() before creating that span element. span1.after(br).after(span2); in this line it is gonna search for span1 element to apply .after() but that element is not there. If you understand clearly about why do we have to use .ready() it has similarity here. Your code should be like this

var span1 = $("<span/>").text("Hello");
var br = $("<br/>");
var span2 = $("<span/>").text("World!");

$("#test").append(span1);
span1.after(span2).after(br);

And remember .after() add elements from left to right so you have to use .after() in the order of 9 to 1 so it will give result 1 to 9.

Hope you got the answer. :)

Tulipwood answered 13/3, 2013 at 10:32 Comment(1)
The explanation here is wrong. span1 contains the first span, regardless of the fact that it's dynamic. the reason .after doesn't work as intended is because span1 isn't in a dom or dom fragment and therefore can't actually have siblings. The same thing happens if you store a reference to an element and then remove it... that reference will now refer to a detached element that similarly can't have siblings.Flavine
S
0

You are creating html dynamically so you need to call append() first and then make a call to after().

You should try like

<div id="test"></div>

JS

var span1 = $("<span/>").text("Hello");
var br = $("<br/>");
var span2 = $("<span/>").text("World!");
$("#test").append(span1);
span1.after(span2).after(br);

order of adding element should be from left to right

DEMO

Sunken answered 13/3, 2013 at 10:21 Comment(3)
What if I can't access the DOM. E.g. the code is part of a function that dynamically creates these two spans separated by the break and returns it to the caller. Like here: jsfiddle.net/s6VdW/10Reeta
In that case you can use append() like return span1.append(br).append(span2);Sunken
No, that produces <div id="test"><span>Hello<br><span>World!</span></span></div> jsfiddle.net/s6VdW/12Reeta
C
0

Try with this one:

var span1 = $("<span/>").text("Hello");
var br = $("<br/>");
var span2 = $("<span/>").text("World!");

$("div").append(span1);
span1.after(br);
br.after(span2);

do .after() when you append first span1.

FIDDLE

Celebrant answered 13/3, 2013 at 10:22 Comment(0)
T
0

The problem is you create span1 dynamically at the same time you use .after() before creating that span element. span1.after(br).after(span2); in this line it is gonna search for span1 element to apply .after() but that element is not there. If you understand clearly about why do we have to use .ready() it has similarity here. Your code should be like this

var span1 = $("<span/>").text("Hello");
var br = $("<br/>");
var span2 = $("<span/>").text("World!");

$("#test").append(span1);
span1.after(span2).after(br);

And remember .after() add elements from left to right so you have to use .after() in the order of 9 to 1 so it will give result 1 to 9.

Hope you got the answer. :)

Tulipwood answered 13/3, 2013 at 10:32 Comment(1)
The explanation here is wrong. span1 contains the first span, regardless of the fact that it's dynamic. the reason .after doesn't work as intended is because span1 isn't in a dom or dom fragment and therefore can't actually have siblings. The same thing happens if you store a reference to an element and then remove it... that reference will now refer to a detached element that similarly can't have siblings.Flavine
B
0

As you can read in the Additional Notes of the after() method:

Attempting to use these methods on a node without a parent has no effect—that is, neither the set nor the nodes it contains are changed.

That's why it didn't work in your code!

Unlike after() you can use .add( elements ) with dynamically created elements without a parent. But beware that it will return a new jQuery object without mutating the old element.

const helloWorld = () => $()
  .add($("<span>").text("Hello"))
  .add($("<br>"))
  .add($("<span>").text("World!"))

$("#test").append(helloWorld());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div id='test'></div>

If templating is what you are looking for, you don't even have to use add(). Just put your jQuery elements in an array and append it to the div.

const helloWorld = () => [
  $("<span>").text("Hello"),
  $("<br>"),
  $("<span>").text("World!")
]

$("#test").append(helloWorld());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div id='test'></div>
Brownie answered 5/6 at 19:13 Comment(0)
T
-1

Try

var span1 = $("<span/>").text("Hello");
var br = $("<br/>");
var span2 = $("<span/>").text("World!");
span1.after(br);

$("#test").append(span1).append(span2);
Taker answered 13/3, 2013 at 10:9 Comment(2)
This displays the two spans, but I still miss the <br/> element. HTML Output: <div id="test"><span>Hello</span><span>World!</span></div>Reeta
This fails because span1 doesn't have a parent that can contain children.Flavine
U
-1

If you want to use the after method, you can try something like :

// Initialize jQuery objects
var span1 = $("<span/>").text("Hello");
var br = $("<br/>");
var span2 = $("<span/>").text("World!");

// First step : Add the first element to your div
$("div").append(span1);
// Second step : Add the differents elements with the add method (note that I inversed the order to work fine because the after is applied to span1 and not to the last added element.
span1.after(span2).after(br);
Ukrainian answered 13/3, 2013 at 10:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.