InnerHTML
Example: When you load a table (as a string) into an existing div, using innerHTML there is no problem, - if the DIV is empty. Even if the string contains functions like <td onclick="bla()"> I could not see any leak.
The problem starts then, when you REPLACE content using innerHTML . It doesn't matter if the content is pure HTML or containing event handlers. This leaks like mad. Replacing plain text with other plain text does not leak. It seems, that the inserted HTML content will be evaluated correctly and would not leak, but the replaced content is not correctly detachted from the parent element, when overwriting by innerHTML. Maybe Microsoft knows why?
That means, if you repalce any content where you want to place new one, you have to remove the old one correctly. There are 2 steps to do:
1. Remove all event handlers from the old content. Set each event handler = null. 2. Destroy all HTML Elements.
The web is plenty of workarounds to get step 2 done. Most of them do not work.
e.g. div.innerHTML = "" before inserting new content // leaks like mad
or div.removeChild(div.firstChild)
This is all nonsence.
THE ONLY CORRECT SOLUTION IS TO USE OUTERHTML to remove the old content. Why?
Imagine a div with a table inside. Whether inserted with innerHTML or by appendChild. Now you want to replace the content of the div using innerHTML. Most solutions on the WEB tells you the following to remove the old content: 1) div.innerHTML = ' before inserting the new content > does not work
2) assign to all TD's: TD.innerHTML ="" > you remove the content of the TD, not the TD itself. (This works ONLY, if the TD does not contain other HTML tags like SPAN,B,I...) 3) loop the whole table and detach each element from the other by using: parentElement.removeChild(ChildElement) > Then you have flying TABLE, TR, TD Elemets that did not disapear from the memory. (Only from your view)
See the difference between innerHTML and outerHTML. OuterHTML contains the Tag, innerHTML not.
Example of one single Div without other HTML Tags in it:
d= documentGetElementById("MyDiv")
d.innerHTML = "" empties the content of the div. The Div is still there
d.outerHTML = "" removes <DIV>......</DIV> AND THE ELEMENT HAS GONE FOR ALL TIME !
d=null;
The correct way to remove our table within the div is the following:
First we remove any eventhandlers from the tree (Table in our example)
Then remove all elements form each other, starting with the deepest child element in the tree. This includes as well span, div or any other tag, that we would find in a table's TD. We use removeChild.
For each removed child we immediately clear the child using OUTERHTML.
Now the table of our example has gone forever and we are free to insert new content into the div container using innerHTML.
To cleanup the div's content of our TABLE example, you need only the following function. As input paremeter you need the parent Element of the content, you want to remove. In our example a reference to the div container.
Use the following function, after that you removed the event handlers. OR expand this function to check, if there is an event handler to be removed of the current node.
This function removes all children recursively. This solution is the ONLY one, that does not create memory leaks using innerHTML as by my tests.
function DeleteChildren(node){
if(node){ for(var x = node.childNodes.length - 1; x >= 0; x--){ var childNode = node.childNodes[x]; if(childNode.hasChildNodes()){ DeleteChildren(childNode); } node.removeChild(childNode); if(childNode.outerHTML){ childNode.outerHTML = '; } childNode=null; } node=null; }
if(node){
for(var x = node.childNodes.length - 1; x >= 0; x--){ var childNode = node.childNodes[x]; if(childNode.hasChildNodes()){ DeleteChildren(childNode); } node.removeChild(childNode); if(childNode.outerHTML){ childNode.outerHTML = '; } childNode=null; } node=null;
for(var x = node.childNodes.length - 1; x >= 0; x--){
var childNode = node.childNodes[x]; if(childNode.hasChildNodes()){ DeleteChildren(childNode); } node.removeChild(childNode); if(childNode.outerHTML){ childNode.outerHTML = '; } childNode=null;
var childNode = node.childNodes[x]; if(childNode.hasChildNodes()){
DeleteChildren(childNode);
} node.removeChild(childNode); if(childNode.outerHTML){
childNode.outerHTML = ';
} childNode=null;
} node=null;
}
There are other functions on the web, that remove all event handlers from a page by a singe function.