Why should y.innerHTML = x.innerHTML; be avoided?

browser, html, javascript, jquery

Solution

This method of "copying" HTML elements from one place to another is the result of a misapprehension of what a browser does. Browsers don't keep an HTML document in memory somewhere and repeatedly modify the HTML based on commands from JavaScript.

When a browser first loads a page, it parses the HTML document and turns it into a DOM structure. This is a relationship of objects following a W3C standard (well, mostly...). The original HTML is from then on completely redundant. The browser doesn't care what the original HTML structure was; its understanding of the web page is the DOM structure that was created from it. If your HTML markup was incorrect/invalid, it will be corrected in some way by the web browser; the DOM structure will not contain the invalid code in any way.

Basically, HTML should be treated as a way of serialising a DOM structure to be passed over the internet or stored in a file locally.

It should not, therefore, be used for modifying an existing web page. The DOM (Document Object Model) has a system for changing the content of a page. This is based on the relationship of nodes, not on the HTML serialisation. So when you add an `li` to a `ul`, you have these two options (assuming `ul` is the list element):

// option 1: innerHTML
ul.innerHTML += '<li>foobar</li>';

// option 2: DOM manipulation
var li = document.createElement('li');
li.appendChild(document.createTextNode('foobar'));
ul.appendChild(li);

Now, the first option looks a lot simpler, but this is only because the browser has abstracted a lot away for you: internally, the browser has to convert the element's children to a string, then append some content, then convert the string back to a DOM structure. The second option corresponds to the browser's native understanding of what's going on.

The second major consideration is to think about the limitations of HTML. When you think about a webpage, not everything relevant to the element can be serialised to HTML. For instance, event handlers bound with `x.onclick = function();` or `x.addEventListener(...)` won't be replicated in `innerHTML`, so they won't be copied across. So the new elements in `y` won't have the event listeners. This probably isn't what you want.

So the way around this is to work with the native DOM methods:

for (var i = 0; i < x.childNodes.length; i++) {
    y.appendChild(x.childNodes[i].cloneNode(true));
}

Reading the MDN documentation will probably help to understand this way of doing things:

- `appendChild`

- `cloneNode`

- `childNodes`

Now the problem with this (as with option 2 in the code example above) is that it is very verbose, far longer than the `innerHTML` option would be. This is when you appreciate having a JavaScript library that does this kind of thing for you. For example, in jQuery:

$('#y').html($('#x').clone(true, true).contents());

This is a lot more explicit about what you want to happen. As well as having various performance benefits and preserving event handlers, for example, it also helps you to understand what your code is doing. This is good for your soul as a JavaScript programmer and makes bizarre errors significantly less likely!

Problem

Let's say that we have a DIV `x` on the page and we want to duplicate ("copy-paste") the contents of that DIV into another DIV `y`. We could do this like so: ``` y.innerHTML = x.innerHTML; ``` or with jQuery: ``` $(y).html( $(x).html() ); ``` However, it appears that this method is not a good idea, and that it should be avoided. (1) Why should this method be avoided? (2) How should this be done instead? Update: For the sake of this question let's assume that there are no elements with ID's inside the DIV `x`. (Sorry I forgot to cover this case in my original question.) Conclusion: I have posted my own answer to this question below (as I originally intended). Now, I also planed to accept my own answer `:P`, but lonesomeday's answer is so amazing that I have to accept it instead.

Original source

Related problems