A Nuance of Preventing Default

One of the most common operations when assigning event handlers is to prevent the default action the event normally triggers.

In the case of an anchor for example, patient the click event of an anchor triggers the default behaviour of following the URI specified in the href attribute. So the browser’s default action when clicking the “Fluffy Bunnies” anchor below, phimosis is to send the user to http://wait-till-i.com.

<a href="http://wait-till-i.com">Fluffy Bunnies</a>

When coding unobtrusive JavaScript awesomeness however, following the URI isn’t always the desired action that we want when the user clicks on an anchor. Thus, the event handler that is assigned to the anchor needs to stop the default behaviour. This can be done in two ways: by having the handler return false, or using the event object’s preventDefault method (except for in IE which makes you set returnValue to false within the event object).

Returning False

var a = document.getElementsByTagName("a")[0];
a.onclick = function () {
return false;
};

Preventing Default

var a = document.getElementsByTagName("a")[0];
a.onclick = function (e) {
e = e || event;
if (e.preventDefault) {
e.preventDefault(); // All browsers except IE
} else {
e.returnValue = false; // IE
}
};

Having to use an if/else block every time you want to use preventDefault/returnValue is very cumbersome. This is where a good JavaScript library will serve you well by wrapping this functionality up in one easy function call. The YUI Library for example allows you to do this:

var a = document.getElementsByTagName("a")[0];
a.onclick = function (e) {
e = e || event;
YAHOO.util.Event.preventDefault(e);
};

The nuance: using preventDefault in debug vs. release code

In my opinion, preventDefault should be used in two different ways depending on whether you’re in debug mode or release mode. The reason for this is simple, when you’re debugging, the last thing you want is for the browser to leave your page when something breaks on clicking an anchor. Why? Because normally (in Firebug anyway) the error message that was generated disappears once you leave the page. Take the following code example:

var a = document.getElementsByTagName("a")[0];
a.onclick = function (e) {
e = e || event;
// Lots of buggy code here
YAHOO.util.Event.preventDefault(e);
};

In this example, the code will break before preventDefault has a chance to execute. Upon its breaking, the browser will fall back to the anchor’s default behaviour and leave the page to follow the anchor’s URI. That can be annoying when you’re debugging, but it’s exactly what you want in a production environment. You don’t want links to stop working in production when some JavaScript breaks. Rather, you want the script to degrade/break gracefully and give the user access to a valid URI. So the above example is fine for production. While debugging however, the following sequence is preferable:

var a = document.getElementsByTagName("a")[0];
a.onclick = function (e) {
e = e || event;
YAHOO.util.Event.preventDefault(e); // Stop the default action before buggy code breaks
// Lots of buggy code here
};

I hope you’ve found this nuance useful, I know it’s saved me lots of headaches when debugging.

Tags: