18

This question might be stupid, or basic.

Can someone explain which is the best method in adding DOM elements. We have these two ways of adding DOM elements.

Scenario: Need to add <strong>Hi</strong> inside an existing <div id="theEl"></div>.

  1. By editing the HTML inside them.

     document.getElementById("theEl").innerHTML = '<strong>Hi</strong>';
    
  2. By using document.createElement().

     var hi = document.createTextNode("Hi"),
     strong = document.createElement("strong");
     strong.appendChild(hi);
     mydiv = document.getElementById("theEl");
     document.body.insertBefore(strong, mydiv);
    

Questions

  1. What is the best way to do? One is a single line, another is about five lines.
  2. What is the performance aspect?
  3. What is the right way or best practise?
  4. Is there any difference between the codes as a whole?

If at all this question is not making sense, please let me know, I will be glad to close this or even remove this. Thanks.


For the close voter, this is not going to be a duplicate of that question. One thing I just noted is, using createElement() preserves the event handlers attached to the element. Even though that's a good point, any kind of basic web page, too has jQuery in them, which provides delegation and such stuff that allow me to have the event attached to the element even after change in HTML.

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
  • 2
    I prefer method 1 for simple HTML insertion. But if I have to generate some nodes using loops, method 2 may be easier. – Raptor Apr 12 '13 at 03:50
  • 2
    http://stackoverflow.com/questions/2946656/advantages-of-createelement-over-innerhtml – KingKongFrog Apr 12 '13 at 03:51
  • 1
    for performance, `innerHTML` is much faster http://www.quirksmode.org/dom/innerhtml.html – Andreas Wong Apr 12 '13 at 03:53
  • One thing I just noted is, using `createElement()` preserves the event handlers attached to the element. Even though that's a good point, any kind of basic web *page*, too has jQuery in them, which provides delegation and such stuff that allow me to have the event attached to the element even after change in HTML. :) – Praveen Kumar Purushothaman Apr 12 '13 at 03:59
  • One huge problem with just setting `innerHTML` crops up when you start to use dynamic data. If you just set innerHTML to be something like `'

    ' + someDataFromUser + '

    '`, you just opened up yourself to XSS attacks.
    – Brad Apr 12 '13 at 04:04
  • The second option doesn't do the same thing as the first. That said, one can't really give good advice with just the above as an example. – Ja͢ck Apr 12 '13 at 04:13
  • @Brad Think about Firebug and Developer tools! :P – Praveen Kumar Purushothaman Apr 12 '13 at 04:15
  • @Jack Okay, make the `insertBefore` as replacing the inner HTML. – Praveen Kumar Purushothaman Apr 12 '13 at 04:15
  • Must the innerHTML be replaced? The scenario says "add X into existing Y". – Ja͢ck Apr 12 '13 at 04:17
  • @Jack Make it replace Y contents with X. :) Sorry about the code there. – Praveen Kumar Purushothaman Apr 12 '13 at 04:17
  • @PraveenKumar, I am not saying users cannot manipulate the page anyway. What I am saying is that there is danger, and at a minimum possibility of broken HTML, if you don't use text as text. Think about the scenario of someone injecting JavaScript into your site via a comment box which is loaded over AJAX. – Brad Apr 12 '13 at 04:18
  • @Brad Yeah, now I get it. That is dangerous. :) – Praveen Kumar Purushothaman Apr 12 '13 at 04:19
  • Yup, I agree that @Brad has a point with poor JavaScripting leading to XSS vulnerability. This is about best practise and not about performance, in this particular case of Brad. :) – Praveen Kumar Purushothaman Apr 12 '13 at 04:25
  • @Jack, I don't think you understand. A proper AJAX response has **absolutely nothing to do** with the scenario I'm talking about. I only suggested AJAX as it is a common scenario. Who cares where it comes from. If you are sticking arbitrary data in HTML, you have a potential for a problem. The server in my scenario has no part in this. – Brad Apr 12 '13 at 04:35
  • @Brad If there's no server, then who's going to inject your page with evil code besides yourself? – Ja͢ck Apr 12 '13 at 04:38
  • @Jack, There isn't enough room in a 500 character comment box to break this entire example down for you. Obviously a server is involved. This is a web application after all. Think this through for a minute. If it is possible to get arbitrary data in a variable (which it is, **especially** in a valid JSON response), and you are just injecting whatever you get into some HTML, then it is possible for what you think is text to get interpreted as HTML. – Brad Apr 12 '13 at 04:41
  • @Brad Does it apply for JSON output too? – Praveen Kumar Purushothaman Apr 12 '13 at 04:42
  • @PraveenKumar, No, it has nothing to do with JSON!!! Look, I'm not even talking about parsing JSON here at all. I don't know why this isn't making sense. If you have a variable in JavaScript that has the value of `` and you plug it into HTML blindly, you will have troubles. It doesn't matter how the data was assigned to the variable. – Brad Apr 12 '13 at 04:43
  • Even if you think you are blocking HTML and all that jazz, what about the username who happens to be `Joe & Schmoe`? Now you have broken HTML because you didn't use the text value correctly. Yes, the browser interprets it immediately, and will almost always get it correct, but the point is still valid. – Brad Apr 12 '13 at 04:44
  • @Brad How can you insert a JavaScript includer (``) and make it get included and run, without creating an element. Coz, in this case, it **needs** to have it initialized to get included. Do you get me? – Praveen Kumar Purushothaman Apr 12 '13 at 04:46
  • @PraveenKumar, Yes, of course you need an element. I'm talking about the situations where `innerHTML` is set, and arbitrary data is concatenated into it. – Brad Apr 12 '13 at 04:47
  • @Brad Yeah okay, if the data from the server is provided under the context of being used as a regular JavaScript string (i.e. no HTML intent) and you blindly add that using innerHTML, that would cause problems. If that's what you meant we're one the same page :) – Ja͢ck Apr 12 '13 at 04:49
  • @Jack, Yes!! Precisely. – Brad Apr 12 '13 at 04:50
  • @Brad It doesn't work locally using `file:///` but when executed from the server, we don't need to use a `createElement`. The JavaScript executes instantly, and yeah, it is a security violation! Wow! Learnt it new! – Praveen Kumar Purushothaman Apr 12 '13 at 04:57
  • 1
    In any case, there are more than one thing to consider here, which is why I cv'ed it for being non constructive; no offence ... it's just that the question should cover a more narrow scope imo. – Ja͢ck Apr 12 '13 at 05:03
  • Okay @Jack, will add more specific stuff to the question, from next time onwards. :) I am good only in answering and not questioning. :P – Praveen Kumar Purushothaman Apr 12 '13 at 05:04
  • Looks like there's a similar one for jQuery here: http://stackoverflow.com/questions/327047/what-is-the-most-efficient-way-to-create-html-elements-using-jquery – Praveen Kumar Purushothaman Apr 12 '13 at 05:12
  • Any reason for downvote? – Praveen Kumar Purushothaman Oct 26 '14 at 13:47

4 Answers4

9

There is no "best" or "best practice". They are two different methods of adding content that have different characteristics. Which one you select depends upon your particular circumstance.

For creating lots and lots of elements, setting a block of HTML all at once has generally shown to be faster than creating and inserting lots of individual elements. Though if you really cared about this aspect of performance, you would need to test your particular circumstance in a tool like jsperf.

For creating elements with lots of fine control, setting classes from variables, setting content from variables, etc..., it is generally much easier to do this via createElement() where you have direct access to the properties of each element without having to construct a string.

If you really don't know the difference between the two methods and don't see any obvious reason to use one over the other in a particular circumstance, then use the one that's simpler and less code. That's what I do.

In answer to your specific questions:

  1. There is no "best" way. Select the method that works best for your circumstance.
  2. You will need to test the performance of your specific circumstance. Large amounts of HTML have been shown in some cases to be faster by setting one large string with .innerHTML rather than individually created an inserting all the objects.
  3. There is no "right way" or "best practice. See answer #1.
  4. There need be no difference in the end result created by the two methods if they are coded to create the same end result.
jfriend00
  • 683,504
  • 96
  • 985
  • 979
5

I actually like a combination of both: createElement for the outer element so you won't be removing any event handlers, and innerHTML for the content of that element, for convenience and performance. For example:

var strong = document.createElement('strong');
strong.innerHTML = 'Hi';
document.getElementById('theEl').appendChild(strong);

Of course, this technique is more useful when the content of the thing you're adding is more complex; then you can use innerHTML normally (with the exception of the outer element) but you're not removing any event listeners.

icktoofay
  • 126,289
  • 21
  • 250
  • 231
1

1. What is the best way to do? One is a single line, another is about five lines.

It depends on context. You probably want to use innerHTML sparingly as a rule of thumb.

2. What is the performance aspect?

DOM manipulation significantly outperforms innerHTML, but browsers seem to keep improving innerHTML performance.

3. What is the right way or best practise?

See #1.

4. Is there any difference between the codes as a whole?

Yes. The innerHTML example will replace the contents of the existing element, while the DOM example will put the new element next to the old one. You probably meant to write mydiv.appendChild(strong), but this is still different. The existing element's child nodes are appended to rather than replaced.

Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
  • This is new. I got another view here: for performance, `innerHTML` is much faster http://quirksmode.org/dom/innerhtml.html. What do you think? – Praveen Kumar Purushothaman Apr 12 '13 at 04:13
  • 1
    I remember looking at those tests maybe a year ago and thinking they were very biased, and writing my own tests and getting pretty much the results I expected. I think it's all chronicled here on SO somewhere. – Dagg Nabbit Apr 12 '13 at 04:15
  • It would be nice to get that link. :) – Praveen Kumar Purushothaman Apr 12 '13 at 04:16
  • 1
    @PraveenKumar, can't find it, but have a look at this: http://jsperf.com/w3c-dom-vs-innerhtml/10 -- notice that the DOM tests perform better than the `innerHTML` tests, except for the "fastInnerHTML" test, which is somehow amazingly fast, but it's not exactly normal use of `innerHTML` and is probably not what PPK had in mind. – Dagg Nabbit Apr 12 '13 at 04:30
  • This is again confusing. The tests seem weird. It is like not the same output or is not scalable. At first, one seemed faster and the same thing seems slow in the long run or if there are more than a set of elements. What do you think? – Praveen Kumar Purushothaman Apr 12 '13 at 04:35
  • 1
    @PraveenKumar, I think the tests are overly complicated and don't represent realistic scenarios. If I remember right, PPK's table test performs much differently if you insert some dummy data that changes from cell to cell instead of just inserting asterisks. Here's a simple test I made a while back: http://jsperf.com/innerhtml-v-dom – Dagg Nabbit Apr 12 '13 at 06:56
  • I don't think performance is the real concern with innerHTML anyway, unless you're talking about something really bad like `foo.innerHTML += bar`. I think if you have some marked-up text or similar, innerHTML is fine. If you're doing something more complex, using the DOM is probably going to be cleaner and less error-prone. – Dagg Nabbit Apr 12 '13 at 07:21
1

What did you mean by best? In just one DOM operation everything is good and shows the same performance. But when you need multiple DOM insertion, things go diferently.

Background

Every time you insert DOM node, the browser render new image of the page. So if you insert multiple child inside a DOM node, the browser renders it multiple times. That operation is the slowest that you will see.

The solution

So, we need to append most child at once. Use a empty dom node. The built in is createDocumentFragment();

var holder = createDocumentFragment();
// append everything in the holder
// append holder to the main dom tree

The real answer

If in the case is that you described, I would prefer the shortest solution. Because there is no performance penalty in one dom operation

Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252