I <3 rspactor

Last night at the RubyJax meeting I was pair programming with one of the fine folks at Hashrocket and he turned me on to rspactor. It is a gem that automatically and continuously runs your rspec tests and alerts you to failures as you code. It is very lightweight easy to use. All you do is execute rspactor from your project root and off it goes. It runs your whole suite of tests to get started and then any tests that are impacted by the work you are doing as you go. There are a few other tools similar to this one. If you aren't already using one, I would highly recommend checking this out. http://rubyphunk.com/2008/3/11/hello-world-introducing-rspactor

Textmate javascript-tools == Awesome

Seriously. If you are coding javascript in Textmate and not using this, you are really missing out. It is a fantastic plugin for Textmate that allows you to very easily run JSLint on your code and compress it with your pick of compressors. Every time you save a javascript file, it will validate it automatically and let you know right away if there are any problems. It will keep you from having the trailing comma issue hit you in IE. This plugin needs to be manually installed, which is easy to do if you have never done it before. All you need to do is clone the git repository into your Bundle directory. cd ~/Library/Application Support/TextMate/Bundles git clone git://github.com/subtleGradient/javascript-tools.tmbundle.git If you want to update the plugin after that, just do a git pull and you are all set. Here is the project link if you want to follow them on GitHub. http://github.com/subtleGradient/javascript-tools.tmbundle/tree/master

One of My Favorite Functions: closest

Sometimes we may have a generic function that could be triggered from a couple of different places. For example, let's say you have an unordered list with sortable li tags inside and clickable anchor tags that fire the same event to do whatever with the acted on list element. New with jQuery 1.3 is the closest function, which will find the closest element matching the selector, including self. That means that in the scenario defined above we can have a function that looks like this to handle the event. [js]function() { var element = $(this).closest("li"); ... }[/js] Pretty clean code and it will work as long as the event is triggered anywhere from the target li all the way down through any of its children. This function is very similar the the parents function that we all know and love. That, of course, will not include the starting element in the search though.

When to Extend jQuery

More often than you might think. I have found that writing jQuery extensions is a clean and readable way to write not only plugins, but also application and page specific code. Recently there have been two scenarios where I found it appropriate to write some extensions. The first is when you are using a plugin in multiple places and have a common way of invoking and interacting with it in your application. I was working with a modal window that was popped from multiple places, so I wrapped the modal plugin in my own extension that knew all the default settings and behaviors for the modal. That way my pages that used it could just invoke my plugin and not have to duplicate all the setup code. This is just an example to illustrate the technique, so please don't bother trying to execute it. [js](function($) { $.fn.extend({ openMyModal: function(options) { //Merge the passed in and default settings, then call the plugin code. this.popmodal($.extend($.logWorkoutResults.settings, options)); } }); $.extend({logWorkoutResults: { settings: { someSetting: 'blah', success: function() { ... } } }); })(jQuery);[/js] So the gist of what we're doing here is providing the common set of settings and function overrides in one place, but still allowing them to be overridden by the caller. The default settings and the passed in settings will be merged and then the plugin will be invoked. You would call it like this: [js]$(".selector").openMyModal({ someSetting: 'blah blah' });[/js] Pretty clean and easy to use, yet still easy to override if a certain page needs to change things. You can really go crazy with this, too. Since it is your extension just using a plugin, you can add all sorts of additional functionality. The other time that it makes a lot of sense to write your own is when you find yourself writing loose functions that take one or more DOM elements as a parameter, or even if your function selects some elements and acts on them. For example, let's look at this plain old function call. [js]MyPage.myFunction($("div.somestuff"), { parm1: 'value' });[/js] Instead of having a loose function that depends on being passed a jQuery element, just rewrite your function to extend jQuery and it gets a whole lot cleaner. [js]$("div.somestuff").myFunction({parm1: 'value'});[/js]The inside of the function is easy to change, too. The old one would have looked like this: [js]var MyPage = { myFunction: function(elements, settings) { elements.each(function() { //do stuff with 'this' }); } };[/js] But now it will just look like this: [js](function($) { $.fn.extend({ myFunction: function(options) { this.each(function() { //do something with 'this' }); } }); })(jQuery);[/js] So the implementation code doesn't look that much different, but the calling is a whole lot cleaner and easier to follow. You can just include that extension at the top of your page's js file or where it makes sense.

Live Event Handlers

If you are modifying the DOM on the fly, then you have probably noticed that any event handlers you attach don't work on elements added after page load. Let's say you are making an ajax request and your server is returning an html response that you replace a portion of your DOM with. All the normal event handlers that were applied at page load were not applied to these elements, since they didn't exist at that time, and so now you have a bunch of stuff on the screen that doesn't work. Your first thought might be to re-add all the event handlers after the DOM update is complete. This would get the job done, but wouldn't be very efficient and would require the event attachment code to be in multiple places. A better approach would be to use the "live" function introduced in jQuery 1.3 (or the livequery plugin if you are still on 1.2). Instead of applying directly to the element, it captures bubbled events and checks the target element to see if it matches what is being watched. That way, an event on any element that matches the live's selector will have the event fired. The call is basically the same, except you pass in the name type of event to watch for. [js]$("a.link_to_watch").live('click', function() {});[/js]At the time of writing this post, the event types not supported are blur, focus, mouseover, mouseleave, change, and submit. If you need to attach to those types of events, you will need to use the livequery plugin instead.

Selecting the Next Table Row

If you find yourself with a table of alternating rows, first a visible summary row followed by a hidden detail row, then selecting the next table row is a piece of cake. You may need to do it for any number of reasons, too. For starters, you may want to only turn on the "expand" icon in the summary row if there is actually data in the detail row. We will assume that the detail row contains div.something if there is actually data there. [js]$("table tr:visible").each(function() { ($(this).next().is(":has(div.something)") && $(this).find("img.expand").show()); });[/js] That will select the visible rows in the table and iterate over them. It will check each one to see if it has the div we are looking for and if it does, it will show the expand image. We are taking advantage of the fact that there are all function calls and using short circuit evaluation of the conditional to not run the argument after the && if it fails. One of my favorite Stupid Javascript Tricks. You may also want to actually show and hide the table when the expand icon is clicked. Also pretty easy to do. [js]$("table tr img.expand").click(function() { $(this).closest("tr").next().toggle(); });[/js] That will toggle the table row following the one containing the clicked expand icon. Pretty straightforward stuff, thanks to jQuery.

Auto Select the First Form Element

This is an easy one that I have been asked about a number of times before. I always recommend that you wrap your content area in a containing div to separate it from other portions of the page. Namespacing your DOM will keep your javascript and css from bleeding over into other panels unexpectedly. Hence the div#content. So, to automatically select the first element in the form on your page, all you need is this: [js]$("div#content form :input:visible:first").focus();[/js]If you want the first empty element, then you just need to change it to:[js]$("div#content form :input:visible:first[value='']").focus();[/js]You may be wondering why I did :input:visible instead of just :text, and that is because I want to get any input elements that are on the screen, not just text inputs. Using :input will return input, textarea, select, and button elements. Adding :visible will not only filter out visibly hidden forms, but also type='hidden' input elements as well.

Constructing a Selector Friendly DOM

Your markup is extremely important not only for the display of your application, but also for the complexity and stability of your javascript. There are three important tenets to building a selector friendly DOM.

1. Keep it Lean!

I cannot stress the importance of the markup of your pages enough. Some people think of the markup as being just the browser's input feed, but it is actually much more than that. It is the data model for a face of your application and has three separate but related users: the browser, the javascript, and the css.

Building your markup with all three of these in mind will make your selectors a lot cleaner and easier to work with. Adding DOM elements that aren't necessary will negatively impact all three of these aspects, so just don't do it. Whatever the reason for adding them to begin with, remove them if you don't need them anymore. Having extraneous stuff in there will also hurt our next bullet.

2. Be Consistent!

Your DOM needs to be consistent. This starts with understanding what all the tags actually are and what they are intended for. For example, a "p" tag is for paragraphs. Are you making a paragraph when you use it? If not, then you may want to consider using something else that is better suited. A "div" is for defining a logical block of elements on the screen. A "table" is for displaying tabular data. If you are using it for your page layout, shame on you!

Having a consistent way of creating your DOM will make it a lot easier to write generic selectors. You can't select all the rows in your form cleanly if some of them are wrapped in paragraphs and some are wrapped in divs.

3. Namespace!

Namespace the major portions of your page. It will allow you to write javascript and css that is specific to a portion of the page and will prevent unintended bleed over into other portions of the screen. The simplest example is a typical page layout with a header, left panel, and content pane. Each of these are unique elements on the screen and should have an id. Every selector that is intended for only that piece should then begin with "div#content" or whatever.

Ids and classes aren't just for css, either. If it makes sense, add a class to the elements that you want to select with your javascript even if it is never mentioned in the css. Those attributes are designed for use with selectors and since we use selectors heavily in both css and javascript, it is perfectly acceptable to add them for one or the other or both.

Also, if an element is meant to be totally unique on the screen, like your content pane, use an id instead of a class to distinguish it. By their nature, ids are unique on the screen and classes are for mass assignment, so using them appropriately gives you one more piece of metadata when interacting with your DOM.