I have this code (running jQuery 1.4.2)
var elementToAdd = $('<h3>').html('header');
var p = $('<p>').html('hello world');
elementToAdd.after(p);
$('div#content').append(elementToAdd);
However, the output is
<div id="content">
<h3>header</h3>
</div>
The paragraph "Hello world" is not added.
What am I doing wrong?
I have been trying out some variations:
This does not work either:
var elementToAdd = $('<div>Header</div>');
var p = $('<p>hello world</p>');
elementToAdd.after(p);
or this:
var elementToAdd = $('<h3>header</h3>').after('<p>hello world</p>');
But this works (on Firefox, at least):
var elementToAdd = $('<div>').after('<h3>header</h3>').after('<p>hello world</p>');
Why?
I don't think .after
works with elements that have not been added to the DOM yet...
Try this
var elementToAdd = $('<h3>').html('header');
var p = $('<p>').html('hello world');
$('div#content').append(elementToAdd);
elementToAdd.after(p);
Edit: Yep, that works alright! http://jsfiddle.net/tu2GY/
Edit 2: ok, I am not extremely good at this, but here goes...
As @Extrakun pointed out, the jQuery documentation indeed notes that the element may not be attached to the DOM...
As of jQuery 1.4,
.before()
and.after()
will also work on disconnected DOM nodes.
So, I took a deep breath and opened jquery-1.4.2.js (in vim :D) and what I found was that whatever is being passed to .after
on an element that has no parentNode
, is being used as a selector string which I think is failing when you are passing a jQuery object. I'll try to post some code of what I mean in a minute or two here... (inside pushStack
method)
ret.selector = this.selector + "." + name + "(" + selector + ")";
The selector
here is what ends up being whatever you pass to .after
. Didn't really make out much after that.
EDIT: To modify the original set, you can .push()
a DOM element (not a jQuery object) into the set.
var elementToAdd = $('<h3>').html('header');
var p = $('<p>').html('hello world');
// Push the DOM element in
elementToAdd.push( p[0] ); // [0] gets the DOM element at index 0
$('div#container').append( elementToAdd );
Instead of .after()
, use jQuery's .add()
method.
var elementToAdd = $('<h3>').html('header');
var p = $('<p>').html('hello world');
// Add the new object ----------------v
$('div#container').append( elementToAdd.add(p) );
This will append it as a sibling like you want.
It returns a new jQuery object with both elements as siblings. Because it doesn't modify the original object, you need to either call it in the .append()
or store the result in a variable to append.
EDIT: (As noted in another answer, you can now use after()
like add()
, in that it returns a new set and doesn't modify the original.)
To explain why, this is because a jQuery object is an Array of DOM elements. A DOM element can be a single element with nested descendants, but not two siblings. So when you do .after()
, you're trying to add a sibling to each single element in the array.
To deal with siblings, jQuery has them stored as additional items in its Array.
So when you create a jQuery object by passing 2 or more sibling elements, it splits them apart, and makes them separate items in the Array.
var $obj = $("<div>div element</div> <span>span element</span>");
This will give you a jQuery object with an Array of 2 items.
$obj[0] is the <div> element
$obj[1] is the <span> element
So if you were to create them separately, you would need to use .add()
to add the new item to the Array.
var $obj = $("<div>div element</div>");
$obj[0] is the <div>
var $span = $("<span>span element</span>");
$obj = $obj.add( $span );
$obj[0] is the <div>
$obj[1] is the <span>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With