Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery : Inserting into newly created elements

Tags:

jquery

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?

like image 896
Extrakun Avatar asked Aug 31 '10 12:08

Extrakun


2 Answers

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.

like image 132
sharat87 Avatar answered Sep 24 '22 11:09

sharat87


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>
like image 35
user113716 Avatar answered Sep 24 '22 11:09

user113716