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?
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.
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:
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.
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
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
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.
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.
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(). God bless and happy coding.