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