tags:

views:

2578

answers:

5

I'm trying to use the append function and encountered this:

$("#details").append('<ul>');
for (var i = 0; i < 10; i++) {
    $("#details").append('<li>something</li>');
}
$("#details").append('</ul>');

It appears that the <li> elements renders OUTSIDE the <ul> tag.

Is this a jQuery bug?

+8  A: 

No, it's a programmer bug. <li>s are attached to their <ul> or <ol>, not to its container. And appending a close tag is nonsensical.

You're basically working as if what you were appending were raw HTML, and it's not; you're actually working with the DOM.

Try this:

var list = $("#details").append('<ul></ul>').find('ul');
for (var i = 0; i < 10; i++)
    list.append('<li>something</li>');

Note: please see (and upvote) Blixt's answer, which expands on a couple different options that are superior for various purposes. It deserves attention and hasn't been getting it.

chaos
Ah, should have known this. Thanks a lot.
Floetic
That will return the `#details` element and put it in `list`. Then the `<li>` elements will be added to the `#details` element. You need to select the `<ul>` element after creating it.
Blixt
Thanks, Blixt. I was trying to research whether `append()` returned the parent or child and wasn't having any luck.
chaos
Here you go: http://docs.jquery.com/Manipulation See my answer though, I changed it to be more concise and correct (because `#details` can theoretically contain several `<ul>` elements.)
Blixt
It is better to put all li's into a string or better an array and append only once at the end. Especially if you have long lists.
redsquare
Closing </li> tags are, indeed, sensical. They're required for XHTML validation.
spoulson
Yes, the closing `<li>` tags are fine and appropriate and you'll note I included them. I meant the `append()` of a lone `</ul>` in OP's code sample.
chaos
He meant the `.append('</ul>')` operation. In the DOM, you don't have an object for closing tags; a single DOM object represents the whole tag and its contents.
Blixt
Gotcha .
spoulson
+5  A: 

I think there's a problem in your loop

for (var i = - i < 10; i++)
    $("#details").append('<li>something</li>');

should be I think

for (var i = 0; i < 10; i++)
    $("#details ul").append('<li>something</li>');

and lose the following from the end

$("#details").append('</ul>');

Working Demo

EDIT:

Based on George IV's comment, in order to avoid appending <li> elements to any <ul> that may be a child of the element with id "details", simply give the <ul> element an id when you append it-

$("#details").append('<ul id="appended">');

for (var i = 0; i < 10; i++)
    $("#appended").append('<li>something</li>');

you may also find this article interesting - 43,439 reasons to use append() correctly

Russ Cam
whoa there! bad selector: "#details ul". what if there is more than one unordered list that is a child of #details?
geowa4
give it an id when you append it and then use the id. I've based the answer on what is given in the question and made no assumptions about the rest of the OP's markup
Russ Cam
much better. flipped vote
geowa4
+11  A: 

Nope, you can't use it like that. append is an atomic operation, which creates the element directly.

// The <ul> element is added to #details, then it is selected and the jQuery
// selection is put in the "list" variable.
var list = $('<ul/>').appendTo('#details');
for (var i = 0; i < 10; i++) {
    // New <li> elements are created here and added to the <ul> element.
    list.append('<li>something</li>');
}

Alternatively, generate the HTML and add it all at once (this will be more similar to your original code):

var html = '<ul>';
for (var i = 0; i < 10; i++) {
    html += '<li>something</li>';
}
html += '</ul>';
$('#details').append(html);

This code is noticeably faster when dealing with many elements.

If you need a reference to the list, just do the following instead of $('#details').append(html);:

var list = $(html).appendTo('#details');
Blixt
+1: nice work dodging the multiple child ul issue.
chaos
I like this solution.
Floetic
A: 

For a small static list, I prefer to unroll into a single expression.

$('#details')
   .append($('<ul/>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
      .append('<li>something</li>')
   );
spoulson
That won't work though, because you'll be appending the `<li>` elements to the `#details` element. You could do it like this: `$('<ul/>').appendTo('#details').append('<li>something</li>').append(...`
Blixt
Pay closer attention to the parens and indentation...
spoulson
You're right, I see now. I find it a bit confusing, but that's just my opinion of course.
Blixt
It's just my style. The indents make it clear to me. All others can resort to, IMHO, less readable loop constructs. I ♥ Functional Programming
spoulson
A: 

I would use something like if you have the data in an Array.

var appendToUl = array.join("

  • + array+
  • ");

    It is much faster

    adardesign