Javascript - efficiently insert multiple HTML elements
Asked Answered
H

3

12

I'd like to create a select element with a list of a user's Facebook friends (obtained as a JSON object). I hardcode <select id="friends"></select> into my HTML, then use the following Javascript code to parse the JSON and insert each friend as an option of the select element:

var msgContainer = document.createDocumentFragment();
for (var i = 0; i < response.data.length; i++) { 
    msgContainer.appendChild(document.createTextNode('<option value="'+response.data[i].id+'">'+response.data[i].name+'</option>'));    
}
document.getElementById("friends").appendChild(msgContainer);

This almost works, except that it inserts &lt; and &gt; instead of < and >. How can I fix it, and is there a more efficient way to insert multiple HTML elements using pure Javascript (not JQuery)?

Hauberk answered 23/6, 2013 at 18:58 Comment(0)
T
25

Not sure why you're creating a text node, but it would seem that you want to create option elements, so you could use the Option constructor instead.

var msgContainer = document.createDocumentFragment();

for (var i = 0; i < response.data.length; i++) { 
    msgContainer.appendChild(new Option(response.data[i].name, response.data[i].id));
}
document.getElementById("friends").appendChild(msgContainer);

Or you can use the generic document.createElement().

var msgContainer = document.createDocumentFragment();

for (var i = 0; i < response.data.length; i++) {
    var option = msgContainer.appendChild(document.createElement("option"));
    option.text = response.data[i].name;
    option.value = response.data[i].id;
}
document.getElementById("friends").appendChild(msgContainer);

It's nice to have a helper function for creating elements and setting properties at the same time.

Here's a simple example of one:

function create(name, props) {
    var el = document.createElement(name);
    for (var p in props)
        el[p] = props[p];
    return el;
}

It can be expanded to cover some specific needs, but this will work for most cases.

You'd use it like this:

var msgContainer = document.createDocumentFragment();

for (var i = 0; i < response.data.length; i++) {
    msgContainer.appendChild(create("option", {
        text: response.data[i].name,
        value: response.data[i].id
    }));
}
document.getElementById("friends").appendChild(msgContainer);
Trachyte answered 23/6, 2013 at 18:58 Comment(8)
Thanks! Is one way more efficient?Flavouring
@1'': I wouldn't give performance a second thought here. Personally, I'd make an element creator helper function that lets you create any element and set a bunch of properties at the same time.Krystakrystal
The second variant is inefficient and pretty bad practice (appending elements in a loop), so the first one is preferred.Viglione
@dfsq: That's not true. They're both appending elements in a loop.Krystakrystal
Yes, bro, it's true. There is a difference between appending elements to document fragment and appending them to DOM. Significant difference.Viglione
@dfsq: They're both appending to the document fragment.Krystakrystal
Damn, my bad! You are right, this is my day. Anyway, I upvoted your answer, so no offence :)Viglione
@dfsq: None was taken. Just making sure everything is clear. :)Krystakrystal
C
0

Try this in your for loop instead:

var o = document.createElement('option');
o.setAttribute('value', response.data[i].id);
o.appendChild(document.createTextNode(response.data[i].name));
msgContainer.appendChild(o);
Correspondent answered 23/6, 2013 at 19:9 Comment(0)
E
0

For those who need similar functionality, you can generate an html snippet using template literals and insert it using innerHTML property. Plus you can set attributes and selected while iterating over the items:

const el = document.createElement('select');
el.innerHTML = ['John', 'Sally', 'Betty'].reduce((acc, prev, i) => {
  if (i === 1) {
    return acc + `<option selected>${prev}</option>`;
  }
  return acc + `<option>${prev}</option>`;
}, '');

const root = document.querySelector('#app');
root.appendChild(el);

In modern browsers this is faster than creating elements one by one imperatively.

Edina answered 20/5, 2022 at 14:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.