Unobtrusive JavaScript and jQuery

Reading "jQuery in Action" spurred Martin to learn about the unobtrusive JavaScript style

Near the beginning of the book, I was struck by the emphasis on the unobtrusive JavaScript movement. Somehow this flew by under my radar, probably because for the last couple of years I spent most of my billable programming time writing C++. My curiosity as I read jQuery in Action recently led me to delve further into unobtrusive JavaScript.

The basic idea of unobtrusive JavaScript is that you separate the behavior of a Web page from the structure of the page. That boils down to keeping the JavaScript out of body section of the page and putting it instead in the head section. This is an extension of the idea of keeping style information out of the body of the page and putting it instead in CSS.

Chris Heilmann has elaborated a bit on this in his seven rules of unobtrusive JavaScript:

  • Do not make any assumptions
  • Find your hooks and relationships
  • Leave traversing to the experts
  • Understand browsers and users
  • Understand Events
  • Play well with others
  • Work for the next developer

Heilmann has also written an online book on unobtrusive JavaScript.

The short answer to most of the questions that come to mind about unobtrusive JavaScript, for example "Doesn't that take a lot of code?" and "How do I navigate the DOM well enough to affect only the elements I really want to modify?", is "Use jQuery," at least according to Bibeault, Katz, and like-minded people such as Simon Willison. That's because jQuery was designed to make this style of JavaScript easier to write by implementing concise DOM selectors and commands.

A jQuery selector function, written jQuery(selector) or $(selector), returns an object containing an array of DOM elements that match the selector. So, for example, the selector function $("table tr:nth-child(even)") returns alternate table rows.

A jQuery command does something with a selector array. To continue the example, $("table tr:nth-child(even)").addClass("even") adds the CSS class "even" to alternate table rows. Elsewhere -- preferably in CSS -- we might define the "even" class within table row elements to have a light-green background.

If we put the jQuery selection and command above in the onload event handler for a page (or, even better, in a jQuery document ready function, which runs after the DOM is complete but before all the images load), we can color all the alternate rows in tables on the page green when the page loads, without mucking up the HTML. This has multiple advantages as far as readability and maintainability.

Suppose you want to change the page so that the alternate rows are gray instead of green? Just change one line of CSS.

What if the number of lines in the table increases, for example, because the table was generated by a database query, and the query has been updated dynamically? What do you have to do to extend the alternate line coloring to the new rows? Just run the same selector and addClass command again at the end of the button-press event code that did the update. At this point, you'd probably want to refactor your code a little, and hoist the selector and addClass command into a colorAlternateLines function called by both events, but I'm sure you get the idea.

Have you used unobtrusive JavaScript techniques, with or without jQuery? How has it worked for you?