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 el开发者_如何学编程ementToAdd = $('<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>
Interesting. Adding a temporary works:
var e = $('<h3>').html('header');
var p = $('<p>').html('hello world');
var result = e.after(p);
$('div#content').append(result);
...So I'm guessing that e.after(p)
returns "p after e", but doesn't actually change e. So it works in a chain, and it works disconnected, but won't work quite the way you're expecting it to work.
'elementToAdd' is not a jQuery object pointing to the element. try this:
var elementToAdd = $('<h3>');
elementToAdd.html('header');
var p = $('<p>').html('hello world');
$('div#content').append(elementToAdd);
elementToAdd.after(p);
Manipulating dom is an expensive operation and its best to do it minimum number of times, you above code can be very easily changed to,
$('div#content').append('<h3>header</h3><p>hello world</p>');
The problem is, inserting disconnected DOM nodes with .before and .after only works in jQuery 1.4 (and derivatives).
<script src="jquery-1.4.js"></script>
<script>
$('<div/>').after('<p>Test</p>').filter('p').appendTo('body');
</script>
For all recent jQuery versions, you can also use an object that gets appended for inserting DOM nodes:
<script>
$("<span/>", {
class: "test",
html: "<p><b>Click me!</b></p>"
}).appendTo( "body" );
</script>
精彩评论