Among JS coders, there tend to be two camps of people.
- The DOM/XHTML strict fanatics, who we all should be praising for their effort to standardize the web.
- The innerHTML creative teenagers, who produce enormous amounts of funny code, without organizing things too much.
These two camps tend to shoud nasty words at eachother, because one has a noble aproach at coding, and another has a fast paced >trial'n'error< aproach (at least thats how people i know/talk to, do things).
Each approach has its benefits: DOM being XHTML compliant (if it makes a difference) and innerHMTL being easy to understand and usually superior speed. But in order to reach those benefits, you'll need to do things right, so here is my version of the innerHTML design pattern.
The innerHTML pattern:
the following pattern-rules are a result of my many years of innerHTML coding.
- NEVER EVER read from innerHTML (var p = node.innerHTML)
- Use buffers to manipulate the HTML you want to insert into the node
- Have in mind that innerHTML will destroy events on all nodes inside the destination node
- Use the fastest methods for string concattenation, when building your HTML-string.
- Re-apply events to all created nodes, after you insert the HTML-string
- Re-construct pointers to created nodes, after you insert the HTML-string
Never read from innerHTML:
- If you need to read the content of your node, using innerHTML, theres something wrong with your code-style/pattern. DOM should be your display-output rather then your datastorage, instead use buffers to store your intermediate variables and values.
- Reading from innerHTML is inconsistent, your input from innerHTML doesnt always return the output and vice-versa
- Reading from innerHTML is sometimes used like this: node.innerHMTL += "string"; THIS IS VERY BAD!! Performance sucks, and you'll end up in pain and agony!
Use buffers to manipulate HTML:
- In your script, you should create a pipeline of actions you apply to the output string. It's fast and ensures that your output is precisely constructed.
innerHTML destroys events:
lets say you do this:
var p = "<div id='test'>testing</div>";
document.getElementById("output").innerHTML = p;
function clicked(){ alert(this.id); }
document.getElementById("test").click = clicked;
p += "<div id='test2'>testing 2</div>";
document.getElementById("output").innerHTML = p;
then the click event of #test is destroyed !
Speed of string concatting and inserting:
- The speed of your innerHTML code, soly rely on how fast you are able to concat/manipulate strings !
//Worlds fastest stringbuffer for Javascript:
function FStringCat(){
var accum = '';
var list = [];
this.push = function(what){
accum += what;
if(accum.length>2800){
list.push(accum);
accum = '';
}
};
this.value = function(){
list.push(accum);
accum = '';
list = [ list.join("") ];
return list[0];
};
}
- You may use this stringbuffer or use "string += string" for small concats.
- Insertion speed also have a little to say though... read this article
Re-Create Events and Pointers after setting innerHTML:
- after inserting HTML, do a quick re-mapping.. unless you have zillions of elements, it wont cost you much to do this.
var str = "";
var output = document.getElementById("output");
for(var i=0; i<20; i++){
str += "<div id='d_" + i + "'>one of many</div>";
}
output.innerHTML = str;
//re-construct:
var arrPointers = [];
for(var i=0, elem; elem = output.getElementsByTagName("div")[i] ; i++){
//re-index your element pointers:
arrPointers[i] = elem;
//re-apply your events:
elem.click = clicked;
}