Adam Wulf

The personal site, tutorials, and projects of Adam Wulf

The undocumented life of jQuery’s .append()

March 19th, 2009 · 12 Comments

Did you know that .append() sometimes moves the nodes you pass into it, and other times clones them? This undocumented behavior may cause you some grief if you’re assuming the first, but seeing the second.

If you’re appending to more than 1 node, then jQuery clones the input and then appends the clones to each of the selected items. If you’re appending to just 1 node, then jQuery does not clone the input, but instead moves the item to that place in the document. These two behaviors can leave you with significantly different results.

To help clarify the situation, and fill the documentation hole, I’ll examine the how the following HTML is affected for each of the two .append() behaviors.

<html>
    <head>
    <!-- scripts will go here -->
    </head>
    <body>
        <p>original text</p>
        <div></div>
        <div></div>
    </body>
</html>

.append() with cloning

First, let’s take a look at a script that will clone nodes and append them. Demo.

$(function(){
	// select the only <p> in the document
	var $dom = $("p");
	var actualNode = $dom.get(0);
	actualNode.iAmReal = true;

	// append the node to a selection
	// of *two* <div> nodes
	$("body div").append($dom);

	// now set the text on our original <p>
	// selection. this will only show up if the
	// <p> is *not* a clone
	$dom.text("updated text");

	$appendedDom = $("body div p");
	// get the node that's *really*
	// in the <div> tag
	actualAppendedNode = $appendedDom.get(0);

	// this will alert "moved!" if it's
	// the real node, "cloned!" otherwise
	alert(typeof(actualAppendedNode.iAmReal) == "undefined" ? "cloned!" : "moved!");
});

In the above example, I select the single <p> in the document, and append it to a selection of two divs. I then update the text in the original <p> selection. What is the output, you ask? The original <p> remains the first node of the <body>, and only it’s text is updated. A cloned <p> tag is added to each of the two <div>s, and the text for these 2 <p> tags is not updated.

So, selecting 1 <p> and appending to 2 <div> tags leaves you with a total of 3 <p> tags.

The resulting DOM structure looks like:

<html>
    <head>
    </head>
    <body>
        <p>updated text</p>
        <div>
            <p>original text</p>
        </div>
        <div>
            <p>original text</p>
        </div>
    </body>
</html>

.append() without cloning

Next, let’s take a look at a script that will move nodes instead of clone them. Demo.

$(function(){
	var $dom = $("p");
	var actualNode = $dom.get(0);
	actualNode.iAmReal = true;

	// append the node to a selection
	// of *one* node
	$("body div:first").append($dom);

	// now set the text on the original item
	// this will only show up if it's not
	// a clone
	$dom.text("updated text");

	$appendedDom = $("body div:first p");
	// get the node that's *really*
	// in the <div> tag
	actualAppendedNode = $appendedDom.get(0);

	// this will alert "moved!" if it's
	// the real node, "clonded!" otherwise
	alert(typeof(actualAppendedNode.iAmReal) == "undefined" ? "cloned!" : "moved!");
});

In this above example, I’ve changed the <div> selector to include only a single div instead of both. Since jQuery is now appending the selected <p> to a single <div> the behavior is changed, and the <p> is not cloned, but instead is moved. Line 13 updates the <p>’s text, just as you’d imagine.

So, selecting 1 <p> and appending to 1 <div> tag leaves you with a total of 1 <p> tag.

The resulting DOM structure looks like:

<html>
    <head>
    </head>
    <body>
        <div>
            <p>updated text</p>
        </div>
        <div></div>
    </body>
</html>

summary

jQuery’s .append() behaves different on it’s input depending on if it’s appending to a single node or to multiple nodes. Appending to more than 1 target node:

  1. will not remove the input from the DOM
  2. will clone the input and append to the selection

but, appending to exactly 1 target node does the opposite:

  1. will remove the input from the DOM
  2. will not clone the input and append to the selection

As far as I know, this behavior is true for all functions in the Manipulation area of the docs.

Tags: javascript · programming

12 responses so far ↓

  • 1 adamwulf // Mar 19, 2009 at 1:03 am

    the undocumented life of jQuery’s .append() – http://tinyurl.com/c78nmz

    This comment was originally posted on Twitter

  • 2 mlane // Mar 19, 2009 at 10:05 am

    The undocumented life of jQuery’s .append() – http://bit.ly/rPtk

    This comment was originally posted on Twitter

  • 3 patternhead // Mar 19, 2009 at 11:13 am

    The undocumented life of jQuery’s .append http://tinyurl.com/c78nmz #query #tech

    This comment was originally posted on Twitter

  • 4 minimalart // Mar 19, 2009 at 2:34 pm

    The undocumented life of jQuery’s .append() http://twurl.nl/1z11ok

    This comment was originally posted on Twitter

  • 5 John Lascurettes // Mar 27, 2009 at 2:59 pm

    I tried to understand this. Even re-read it. I am not the master you are. :)

  • 6 John Lascurettes // Mar 27, 2009 at 3:03 pm

    … I guess I’ll have to stick to Buck’s JQuery for People Who Can’t Program Good.

  • 7 dimensionmedia // Apr 23, 2009 at 12:13 pm

    Code in jQuery? The undocumented life of jQuery’s .append() – http://bit.ly/rPtk

    This comment was originally posted on Twitter

  • 8 paviles // Apr 30, 2009 at 11:42 pm

    [software] Code in jQuery? The undocumented life of jQuery’s .append() http://bit.ly/UQf6T

    This comment was originally posted on Twitter

  • 9 Zac Imboden // Sep 15, 2010 at 3:34 pm

    I don’t know if it works for others, but I need to remove a child element, check for scrolling, then replace that child and THEN prepend a copy of that child to another div.

    I create TWO clones, one to reinsert into its parent, another to prepend to another different HTML element:

    //get the last child of the current node
    //firstcontainer is a div that contains html
    nodeChildren = $(firstcontainer).children();
    tmpChild = $(nodeChildren)[$(nodeChildren).length-1];
    //a clone of the current node’s last child
    curChild = $(tmpChild).clone();
    //a second clone to use elsewhere
    curChild2 = $(tmpChild).clone();
    //remove child element from parent elem
    $(tmpChild).remove();
    //if scrolling stops, return removed child node
    $(firstcontainer).append(curChild);
    //also prepend the child node to another container element
    $(secondcontainer).prepend(curChild2);

  • 10 Muzietto // Oct 5, 2010 at 11:09 pm

    Easy, tiger. This page is full of broken links…

  • 11 Adam Wulf // Oct 16, 2010 at 2:17 pm

    @Muzietto, thanks for the heads up, links fixed.

  • 12 BindraBindu // Sep 24, 2011 at 7:27 am

    Hello Everyone,
    JQuery append () method is used to add or insert one or more additional DOM elements in the set of matched elements .In this article I am trying to show you, how we can use append method in JQuery. I have list of images and I want to append image in element………………………… for more details please check out this link.
    http://mindstick.com/Articles/cc535e4a-41c7-42f2-b301-d3ecb59ceb01/?JQuery%20append%20method

    Thanks !!!!!!!

Leave a Comment or