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.

CSS Computed Style

Programmers who are new to javascript are often delighted to discover that it's remarkably easy to modify the style of some existing DOM element, like so:


var myDiv = document.getElementById('myDiv');
myDiv.style.left = '10em';
myDiv.style.backgroundColor = '#369';

The above code snippet will grab a reference to the element on the page whose id is myDiv, and modify that element's .left css property to '10em' and its .backgroundColor css property to '#369'. Nothing earth-shattering here.

Conversely, javascript programmers are often dismayed that the following may or may not work:


var myDiv = document.getElementById('myDiv');
myDiv.style.top = parseInt(myDiv.style.top) + 100 + 'px';

Notice that I said may or may not work. In what cases will it work and it what cases won't it work? Glad you asked (because the answer is easy). Read on to learn more.

Continue reading CSS Computed Style

The .call(..) and .apply(..) functions

Two functions in Javascript that don't seem to get a whole lot of attention are the .call(..) and the .apply(..) functions. Both of these functions have a similar purpose; the major difference lies in how you plan to pass parameters. If you remember from the last blog entry, we examined briefly the .apply(..) function when we were creating a cross-browser solution for setTimeout(..).

In this entry, I want to focus more on the core purpose of these functions. This will eventually lead me into a future blog entry in which I talk about a solution for IE's lack of 'this' keyword support when using attachEvent(..).

But first we must understand more thoroughly what .call(..) and .apply(..) allow us to do. Read on to learn more.

Continue reading The .call(..) and .apply(..) functions

setTimeout Revisited

In my last article, I talked about the problem of passing object parameters to a setTimeout(..) function and how that problem can be solved by using closures. While that method works, I failed to mention that there is an alternative approach if you happen to have the luxury of developing only for the Netscape/Mozilla model (lucky you).

Now, before you stop reading because you think a technique that only works in Mozilla doesn't have much value, let me say that after I explain this technique, I'm going to explore a way to duplicate the technique in IE.

But first things first. Let's explore what setTimeout syntax Mozilla offers us to handle this problem.

Continue reading setTimeout Revisited

Closures Shmosures

Ever heard those javascript snobs talk about closures? "Closures" they'll say "are one of the most powerful concepts in javascript, but they can cause a lot of problems (like memory leaks) if you don't know what you're doing."

I say PHOOEY! Throw caution to the wind and use closures. Personally, I think the warning against closures is just so the javascript elite can continue to feel "elite." No one can dispute the benefits of closures; they're just way too convenient not to use. And anyone who throws the "memory leak" excuse at you is probably referring to IE6's well know memory leak problems (and we can only hope that IE7 will resolve those issues).

So obviously I'm going to talk about closures, but for the sake of simplicity, I want to only focus on one specific technique that involves closures: passing object parameters to a setTimeout(..) function. Read on to learn more.

Continue reading Closures Shmosures