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 | function (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.