How to create an empty, non-null jQuery object ready for appending?

I want to append some html to an empty non null jQuery object only in the loop but it's not working unless I create an object and add an html tag during creation. How can I create an empty jQuery object and be able to add html to it later on?

//var $new = $().add("");  //can't use this object in the loop
//var $new = $([]);        //can't use this object in the loop
//var $new = $();        //can't use this object in the loop
//var $new = $("#nonexistingelement"); //can't use this object in the loop
var $new = $().add("<tr>");  //works but I don't want to add any html at this point. 

$.each(.....)
  {
    $new.append("<sometag>");

});

alert($new.html());  //should display some html

Addition: http://jsfiddle.net/vfPNT/


Solution 1:

Your problem here is that there aren't "null" jQuery objects that can't be appended to and "empty" ones that can be. You've already identified several ways to create an empty one, and while there may be more, it doesn't matter - what you're trying to do simply won't do what you expect it to, no matter how you start off, because...

...append() modifies the DOM, not the jQuery object. And an empty jQuery object has no DOM! Tomalak had the right idea, though you may not have understood it.

I'm going to make three observations about jQuery that you're probably already aware of, but which are useful in understanding the remainder of this answer and therefore may benefit future readers:

  1. A jQuery object is fundamentally a set of DOM elements.
  2. Some jQuery methods operate on the set, and some operate on the nodes in the set.
  3. Some jQuery methods operate only on (or retrieve information only from) the first node added to the set.

With these three observations in mind, let's consider your example:

// 1. create an empty set somehow (doesn't matter how)
var $new = $();

// 2. iterate over something
$.each( ..., function( ... )
{
  // 3. construct a DOM fragment from HTML, and append it
  $new.append("<sometag>"); 
});

// 4. try to display HTML corresponding to the jQuery object
alert($new.html());  

In this example, step #3 will fail to do anything useful because the purpose of append() is to take whatever DOM elements it is given and append them as children to each DOM element in the set. Since $new is an empty set, there are no elements to append to, and... nothing happens. Step #1 is working just fine - but by creating a set without any DOM elements in it, you've set yourself up to fail when you try to use methods that exist to modify the DOM! Reference Observation #2... to modify the set, you need to call a method that actually operates on the set.

Ok, so let's say we use the set modification method add() instead:

  $new = $new.add("<sometag>");

Now we're good, right? Each pass through the loop will create a new jQuery object consisting of the previous set + a newly-created element. Well...

...this will just cause step #4 to do something odd. See, html() is one of those methods I mentioned in Observation #3 - it operates only on the first element in the set. So instead of a sequence ("<sometag><sometag><sometag>...") you're only gonna get a HTML representation of the element created on the first pass through the loop ("<sometag>"). Except... You're not even going to get that, because html() creates a representation of the element's children - so what you're really going to end up with is ""...

This was all just a big disappointment: you started off working with the set (Step #1), then tried to operate on the DOM (Step #3), and finished up by trying to pull data from one DOM element (that didn't exist) (and wouldn't have had any data if it did) (Step #4).

The solution you finally came up with isn't terrible - you're essentially opting to add one root element to the set starting out, and operate entirely on this DOM fragment until you're done adding new elements and are ready to operate on them. You've omitted it from your revised example, but html() would work too, since it would simply dump the contents of your root element.

But just to be complete, I'll give you a final example that works on the set, starting with an empty jQuery object:

var $new = $();
$.each( [1, 2, 3, 4], function(i, v)
{
  $new = $new.add("<div>");
});

alert($new.length == 4); // true

// alerts: <div></div><div></div><div></div><div></div>
alert($("<div>").append($new).html()); 

Solution 2:

Document Fragments are perfect for this; creates an empty object ready for appending. :)

$(document.createDocumentFragment())

Solution 3:

Your object $new is an empty selector, so append has no sets to append to.

add is required to add a DOM node, and then you append to those DOM nodes. Don't think you can avoid starting with an .add.

Solution 4:

i testet the above solution but it did not work for me, it always stayed as empty jQuery object...

if anybody interested, here is my solution:

var jQueryElements = [],
    $new;

$.each( [1, 2, 3, 4], function(i, v){
  jQueryElements = jQueryElements.push($('<div>').get(0));
});

$new = $(jQueryElements);