You're Using jQuery.html() Wrong!

Well, you probably are doing it wrong. jQuery’s html function is a very nice way to replace the contents of an element with new contents. Its usefulness is supposedly limited, though, according to the API documentation for this method. Every day jQuery users use this powerful method in a way that it was never meant to be used, and it works, but does that mean we should still do it?

What Am I Doing Wrong?

If you take a look at jQuery’s API Documentation for the html function, you’ll see that it has 3 method signatures. The first method signature has no arguments, so it’ll just return the HTML within that element. The other two signatures take a single argument: a string or a function that returns a string. Wait! It doesn’t take a DOM element? or a jQuery object? That’s right, html doesn’t accept anything except strings.

How I Learned That I Am a Bad Programmer

Instead of just telling you what you should be doing instead or why html still works when you send in elements, I’m going to walk you down my path of discovery. It all started last week when I was exploring LayoutManager for Backbone. I was looking through the code that was generated using the Backbone Boilerplate utility for Node.js to give myself a better idea of how LayoutManager is used, when I saw this little snippet of code:

1
$("#main").empty().append(layout.el);

Confusion

I thought to myself, “Why didn’t they just use $('#main').html(layout.el);?” This puzzled me for a bit since I had recently learned (as shown in the Subview Rendering Trick article) that html first calls empty within itself, so there was nothing gained except maybe making it a little clearer that empty is called. Well I shirked that off to the side and decided not to think much of it until I came across the same code within the documentation for LayoutManager. So I decided to ask the developer why he would use empty().append() rather than html(). I was pointed to an article that the author had written about how html didn’t support this method signature.

Checking Out the Source

I checked it out myself, and sure enough the jQuery documentation did not support this signature. Well, if it doesn’t support the signature, then why does it still work? I decided to use James Padolsey’s jQuery Source Viewer to look into it. Here’s a stripped down version of the source for html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function (value) {
var elem = this[0] || {};

if (value === undefined) {
return /* HTML string */;
}
if (typeof value === "string" && /* Looks like HTML code*/) {
//Use `cleanData` and `innerHTML`
elem = 0;
}
if (elem) {
this.empty().append(value);
}
}

Remember, this is just a gist of what the source looks like for html. If you want to see the full source you can go here.

Let’s walk through this code for a bit. First it sets elem to either the first element in its list of elements or an empty object. Then it checks to see if you passed in any arguments and sends back an HTML string if you didn’t. Then it checks if we passed in a string. If we did, then it uses cleanData to remove event handlers and extra data bound to the elements, then insert the new contents via innerHTML. Then, if elem is truthy (it was set to zero at the end of the last if statement to prevent this from being true), then that means that the argument was neither undefined or a string (so it should be a function), so we’ll run it through empty().append(value).

The Realization

Well, that means it DOES support DOM elements and jQuery objects because append does! Not only is this true, but since we’re using append to catch the case where the argument was a function, why do we bother using the second if statement? We can use append for the cases where it’s a string too! Wouldn’t this be a great case of DRY (Don’t Repeat Yourself)? Well that’s what I think anyway.

The jQuery Guy

I decided to put an issue up on the API’s GitHub area letting them know how I felt about this. At the time of this writing, I haven’t received a reply, but on the previous conversation (the one that I had with the author of LayoutManager) a jQuery team member posted this:

That will get you into trouble. Just because jQuery is open source does not mean that nuances of the current source code define the API. That is what http://api.jquery.com does. Every major release, we have people complain that we “broke their code” because we changed undocumented internals, precisely because they figured they could just read the source and expect it to work that way in future versions.

While he does have a point, I don’t see why they would make changes in a way that would remove empty().append() from there.

The “Right” Way

As much as I love how simple it is to use html to insert DOM nodes and jQuery objects, I have to concede that it just isn’t “right”. If you want to keep checking the source code each time there’s an update to make that the new version still uses .empty().append() in there, then by all means keep sending in those nodes and objects. But as a “good” JavaScript programmer, I should – and you should – start using .empty().append(). God bless and happy coding.

Author: Joe Zimmerman

Author: Joe Zimmerman Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.