Building HTML in jQuery and JavaScript
It can be a pain to create HTML elements in JavaScript. In this article I will outline a few ways I deal with HTML. First, we’ll look at whether to use an HTML string or a jQuery object, then look at my little HTML string builder utility and finally get some links to templating libraries for building more complex HTML.
HTML String, or jQuery Object?
The first question you have to ask yourself is whether or not it makes sense to build out HTML as jQuery objects, or if you require the speed of building strings. In jQuery 1.4 you can built HTML objects that have events attached. Consider the following code.
$("<input/>", {
id: "permissionsInput",
name: "permissions",
type: "checkbox",
click: function(){
update();
},
checked: "checked"
}).appendTo("#myForm");
You can see here that not only can you build out HTML with attributes, but you can attach events (like click) too. This ability was added to jQuery in version 1.4.
If you were doing this 100 times though, it might be very slow. The better way to do it would be to build out the HTML strings first, and then attach events later with jQuery’s live or delegate methods.
Building HTML Strings
So now you want to build an HTML string because you have a lot of elements to build and you can attach events later. There are basically two ways to do this. You can build one long HTML string and append it:
var data = ["a", "bunch", "of", "things", "to", "insert"];
var html = ‘’;
for (var i=0; i < data.length; i++) {
html += "<td>" + data + "</td>";
}
$("#tablerow").append(html);
Or you can use an array which is typically a little faster.
var data = ["a", "bunch", "of", "things", "to", "insert"];
var html = [];
for (var i=0; i < data.length; i++) {
html[html.length] = "<td>" + data + "</td>";
}
$("#tablerow").append(html);
Building Complex HTML Elements
When you are building more complex HTML, things get a little hairy in the code. Take our previous example with jQuery and turn it into raw HTML building:
html = ‘<input id="permissionsInput" name="permissions" type="checkbox" checked="checked">’;Not bad, but what if those attributes were set programmatically? This is typical.
html = ‘<input "’ + inputId + ‘" name="’ + inputName + ‘" type="’ + inputType + ‘"’ + (isChecked ? ‘checked="checked"’ : ‘’) + ‘/>’;
Yuck! So to solve this I wrote a little ditty function called buildHTML. The code isn’t perfect and it could be written better (please do) but it looks like this:
// my little html string builder
buildHTML = function(tag, html, attrs) {
// you can skip html param
if (typeof(html) != ‘string’) {
attrs = html;
html = null;
}
var h = ‘<’ + tag;
for (attr in attrs) {
if(attrs[attr] === false) continue;
h += ‘ ’ + attr + ‘="’ + attrs[attr] + ‘"’;
}
return h += html ? ">" + html + "</" + tag + ">" : "/>";
}
So now our code for building that same input becomes:
html = buildHTML("input", {
id: inputId,
name: inputName
type: inputType
checked: isChecked
});
Nicer, huh? Get the gist for buildHTML and examples. And by all means fork it and make it better.
Templating
Another way to build out more complex HTML is using templating. John Resig has a great article and some code examples for JavaScript Micro Templating
There is a templating language called mustache that I see a lot of people using. Also, there has been some proposals for templating being built into jQuery’s core, however for now there is a jQuery plugin on github jquery-tmpl. Rey Bango wrote an article explaining using jQuery templating.
If you have any other HTML building tips, please share!
13 comments
i suppose i’ll be marginally helpful, http://github.com/fernmicro/JUP
HTML building with JS will forever be a topic of much dispute. I don’t know which approach is best but I think the only appealing aspect of HTML strings is the speed offered by the way jQuery plays with innerHTML and document fragments. I agree with you — beyond that, long HTML strings are YUCK!
I like your approach, but it does need some refining :)
A slight improvement on this:
Combining conditions (plus strict equality check) and using regex to test for
attrvalue:Actually, since there are so many other boolean attributes (
isContentEditable,autoplay,async,draggable,defer… most of these are HTML5), it might be better to just assume ifattrs[attr]is a boolean thenattris a boolean property:Thank you James! I’ve updated the buildHTML function and the gist in the article.
That buildHTML function is horrible… and pointless, since with jQuery 1.4 you can pass attributes directly to the jQuery function when building HTML.
How about client-side XSLT? When you need to generate large amounts of HTML on the client and this process involves complex logic, then I think XSLT is very handy.
Argos, the
buildHTMLfunction is for building strings in a sane manner, you don’t get the same performance building jQuery objects.jQuery 1.4+ automatically caches the DOM fragment created when you go the $(‘ ’) route, which is supposed to speed that up significantly on loops. As long as you don’t insert the elements into the DOM until you’ve generated them all, it shouldn’t be that slow.
It would be interesting to see some benchmarking between the two approaches.
jQuery 1.4 uses document fragment caching if you are inserting the same exact html you’ve inserted before. If you are setting attributes dynamically from JavaScript to built the html then there is no way to cache a bunch of unique elements.
The way I’ve heard John explain it, I was under the impression that if you do this:
And then:
The second div would still be built from a cached fragment before adding those properties to it.
Yeah that is true, but you are still doing two processes by building that second object so it isn’t a 100% cached fragment. You are much better off building a string.
@ JimB..ur page doesnt exist.
What about if the attribute is a javascript reserved word? I’m using the label tag, and I want to set the for attribute, but for is a reserved word so I get a syntax error.
Is it possible to ‘build’ HTML to inject into head of document using jquery? for example, I have groups on my Ning network based on geolocation, however I have no access to the HEAD of the groups. I can however use a text box to change style. What I’d like to accomplish is to inject geo tags into the head of the document so that the groups have unique locations….any help would be much appreciated. great tutorial!