- Normal
- |
- Widen Column
- |
- Larger Text
Here i'll show a technique to create complex DOM structure without using innerHTML. Consider the following html snippet:
<div class="content">
<p style="color: #f0f0f0;"> This is a paragraph </p>
<form action="/action.do" method="post">
<label for="myinput">Label </label>
<input maxlength="255" name="myinput[]" size="20" type="text" />
</form>
</div>
You want to create this form on the fly. The fastest technique is to write the html as a string and use innerHTML to append it in the page where you want. But using html inside javascript violates separation of concerns and is also not fun. You have to write a long string and then something breaks because you used single quotes instead of double or vice versa when quoting the node attributes. Makes the code look messy and unmanageable.
My favorite technique up till now was to use jQuery to create DOM fragments as shown here and in detail here. This is cleaner than the pure innerHTML case and you can use jQuery's elegant functional chaining to style and modify the DOM. But the styling and modifying bit happens after insertion into the document. So I wondered whether this process is slow and if can we write something that is not ugly like an innerHTML DOM string but faster than the jQuery method.
Lets think of the above HTML code snippet as a form object (a UI object or module as I like to call it) and write it as follows:
var my_form = {
tag : 'div',
className : 'content',
content : [
{tag : 'p',
style: 'color:#f0f0f0;',
text: 'This is a paragraph'
},
{tag: 'form',
action: '/action.do',
method: 'post',
content: [
{tag : 'label',
for: 'myinput',
text : 'My Label'
},
{tag : 'input',
type: 'text',
size : '20',
maxlength : '255',
name : 'Myinput[]'
}
]
} // form tag ends
]
};
Now yes, you might get lost in the braces and brackets here but this looks well indented and clean to me – more manageable. Now I need to run though this hash, create as well as style nodes within a document fragment and then finally append the fragment in the document. So, in theory, since all the DOM modification is happening inside a fragment, its faster than the jQuery way.
So, we take this hash and send it through the code below to be processed and give us the html we need. I think i'll call it the Wall-E function (I like to give names to stuff -live or inanimate):
MyApp.wallE = function wallE(dom_object) {
// tags are created here - private method
function _createTag(obj){
var tag = document.createElement(obj.tag);
for(var attr in obj){
if(!/tag|text|content|className|append/.test(attr)){
tag.setAttribute(attr, obj[attr]);
}
if(attr === 'text') {
tag.appendChild(document.createTextNode(obj[attr]));
}
if(attr === 'className') {
tag[attr] = obj[attr];
}
if(attr === 'append'){
tag.appendChild(obj[attr]);
}
}
if(obj.hasOwnProperty('content')){
for(var elem = 0, len = obj['content'].length; elem < len; elem++){
tag.appendChild(_createTag(obj['content'][elem]));
}
}
return tag;
}
var fragment = document.createDocumentFragment(); // create a document fragment
// create the tags as specified in the hash "my_form" and append to the fragment
fragment.appendChild(_createTag(dom_object));
// return the fragment to be finally added to the document
return fragment;
};
The way you'll use this method is as follows:
document.getElementById("container").appendChild(MyApp.wallE(my_form));
or if you use jQuery:
$('#container').append(MyApp.wallE(my_form));
Performance Test
I used JsPerf to benchmark this method against the jQuery technique. I have written the tests here and the results show that, on an average in most browsers, the recursion method is about 60% faster than the jQuery method. The image below is a snapshot of the results of my test run by different people on their browsers.
Of course, the question that can arise is how much html can i create with this since recursion is memory intensive? I'd say we keep this limited to small snippets (like the alert box in the demo below). Let me know your thoughts while i google for tail recursion.
Demo
Click on the button below to create a fancy alert box. You can download the code here.
Filed under: Javascript
How about some bookmarking love?
Post To Twitter Bookmark on Delicious Bookmark on Digg Share on Facebook Update On Friendfeed Bookmark on Reddit Bookmark on Mixx