Preventing the Default Action

A few days ago, a friend of mine sent me a nifty "view switcher" he wrote in javascript. Unfortunately, he was having a problem in Firefox when switching views. In this case that meant swapping a series of ViewItems (DIVs wrapped up as custom javascript objects) when a view switch was requested by the user. The problem was that in Firefox, switching views would "launch" the user back to the top of the page (becuase he was using "#" for the .href property of all of his view/switch links.

This was happening despite his explicit use of return false at the end of his view switching function in an attempt to prevent the default action of clicking on a link. To understand what he was trying to do, take the following, valid example:

VALID EXAMPLE (DOM LEVEL 0)

function launchYahoo()
{
  window.open('http://www.yahoo.com');
  return false;
}

<a id = "yahooLink" href = "http://www.yahoo.com" onclick = "return launchYahoo();">Yahoo</a>

The return false statement in the function launchYahoo(..) ensures that the default action will be prevented. What is the default action? That depends on the element. In this case, it's an <a> tag, so the default action would be for the browser to link to www.yahoo.com. This is precisely what we want to prevent, since our launchYahoo(..) function does this for us in a separate window.

Now, let's look at the following invalid example:

INVALID EXAMPLE

<a id = "yahooLink" href = "http://www.yahoo.com">Yahoo</a>

function launchYahoo()
{
  window.open('http://www.yahoo.com');
  return false;
}

var yahooLink = document.getElementById('yahooLink');
yahooLink.addEventListener('click', launchYahoo, false);   // use .attachEvent for IE

The above code sample will not prevent the default action, as the first example will, and this is exactly what my friend was trying to do. Why won't this work? Because return false only works for DOM Level 0 event hookups, and in the second example, we've used the more modern method of wiring up events, addEventListener(..) (attachEvent(..) for IE).

So how do you prevent the default action when you've wired up your events using the more modern technique? Not surprisingly, there are two ways: the W3C standard way, and the proprietary IE way.

function preventDefaultAction(evt)
{
  if (evt)
  {
    if (typeof evt.preventDefault != 'undefined')
      { evt.preventDefault(); }                        // W3C
    else
      { evt.returnValue = false; }                     // IE
  }

  // safey for handling DOM Level 0
  return false;
}

Now we can modify our original sample to prevent the default action for either DOM Level 0 event wire-ups, or for the more modern technique in either W3C browsers or IE.

<a id = "yahooLink" href = "http://www.yahoo.com">Yahoo</a>

function launchYahoo(e)
{
  window.open('http://www.yahoo.com');
  return preventDefaultAction(e);               // 'return' is to handle DOM Level 0
}

var yahooLink = document.getElementById('yahooLink');
yahooLink.addEventListener('click', launchYahoo, false);   // use .attachEvent for IE

It's important to remember that if you want to prevent the default action of DOM Level 0 events using the preventDefaultAction(..) function we just wrote, you'll need to use return preventDefaultAction(e). If you're sure you only need to worry about events wired up with .addEventListener(..) or .attachEvent(..), then you can safely omit the return keyword (but since it doesn't hurt anything, my recommendation is to simply use it all the time).

Preventing the default action can be a very useful trick. The example in this blog entry is a particularly good once becuase it illustrates, not only how to prevent the default action, but also illustrates how the technique provides a good down-level experience for users who don't have javascript. Notice that a user whose browser does not support javascript will simply get a static HTML link. And without javascript, the default action won't be prevented, so the user will still be able to use the link for navigation — perfect!

Comments welcome.

2 Responses

  1. iceman2g Says:

    I had a chance to review several of your postings and must say you do a great job of explaining things. Keep up the good work.

  2. Stephen Stchur Says:

    Why thank you! I must admit, the regularity with which I've been posting hasn't been great lately, but it's nice to see that past posts are still relevant and helpful to people. Hopefully I'll have some new posts coming soon.

Got something to say?

Please note: Constructive criticism is welcome. Rude or vulgar comments however, are not and will be removed during moderation.