Anonymous function quick tips

Anonymous functions are those functions that you declare "on-the-fly" in your ECMAScript code. For example:

setTimeout(function() { alert('hey there!'); }, 2000);

Notice how the function that is being passed to setTimeout(..) is declared on the spot, at the very moment we need it. There isn't necessarily anything wrong with doing this, and sometimes it can be quite useful indeed.

There is something you need to watch out for though, and it's pretty important: using lambda functions as event handlers.

Continue reading Anonymous function quick tips

IE Bug dealing with CSS custom cusors

Welcome to another addition of Beating IE into submission!

Before I get started though, I have to make a confession. This article won't be so much about beating IE into submission as it will about IE having beaten me into submission!

Unfortunately, this is one case I wasn't able to come up with any great solutions. All I'll be able to offer at the end of this article, are three (relatively unsatisfying) work-arounds. Which one is least-evil… I'll leave that up to you.

So what is this mysterious bug I'm referring to? Read on to find out.

Continue reading IE Bug dealing with CSS custom cusors

Equals vs Strictly Equals (== vs ===)

Pop Quiz:


alert(2 == '2');   // true or false?
If you answered false, well… sorry. You'd be wrong. How about this:
function Steve()
{
  this.toString = function() { return 'Steve is cool!'; };
}

var s = new Steve();
alert(s == 'Steve is cool!');   // true or false?

False? Actually, no, it's true.

Kind of puzzling isn't it?

Read on to find out what's going on here.

Continue reading Equals vs Strictly Equals (== vs ===)

The IE Resize Bug (revisited)

To see the resize demo in action, browse to the revised Resize Demo Page.

In my last blog entry, I talked about an IE reisze issue (IE failing to properly distinguish between a resize that happens to the <body> element and one that happens to the window (or viewport)).

In that blog entry, I proposed a solution for getting around this issue by ditching IE's built-in resize event entirely and writing some custom code to manage it instead. Specifically, the technique centered around an absolutely positioned DIV whose CSS instructed it to fill the viewport. We then used a bit of javascript (executed at regular intervals) to monitor the size of the DIV.

While this technique worked in my sample page, it failed when put to the test in a real world scenerio. The major problem I ran into was that if the <body> element were manually made smaller or larger any time during the resize logic (something you might want to do to manage scrollbars and page layout) some strange behavior would ensue.

Given that my technique turned out to be less robust that I would have liked, I went back to the drawing board to try to come up with a better design.

What I ended up with was a similar technique, but one that didn't require any CSS (which is a plus) and which centered around a getViewportSize(..) function courtesy of James Edwards (aka Brothercake) and Cameron Adams (highly recommend picking up their book: "The Javascript Anthology").

So enough of my babbling. Let's take a look at the revised sample:


<!DOCTYPE html PUBLIC "-W3CDTD XHTML 1.0 TransitionalEN" "http:www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

  <head>
    <script type = "text/javascript">
   function resize()
   {
    var currentSize = getViewportSize();
    if (currentSize[0] != g_prevSize[0] || currentSize[1] != g_prevSize[1])
    {
     g_prevSize = currentSize;
     debug.value = 'the window was resized: ' +
                   document.documentElement.clientWidth + ', ' +
                   document.documentElement.clientHeight;
    }
   }

   function init()
   {
    window.debug = document.getElementById('debug');
    window.g_prevSize = getViewportSize();
    setInterval(resize, 100);
   }

   function grow()
   {
    var p = document.createElement('p');
    p.appendChild(document.createTextNode('This is a paragraph'));
    document.body.appendChild(p);
   }


   function getViewportSize()
   {
    var size = [0, 0];
    if (typeof window.innerWidth != 'undefined')
    {
     size = [ window.innerWidth, window.innerHeight ];
    }
    else if (typeof document.documentElement != 'undefined' &amp;&amp;
             typeof document.documentElement.clientWidth != 'undefined' &amp;&amp;
             document.documentElement.clientWidth != 0)
    {
     size = [ document.documentElement.clientWidth, document.documentElement.clientHeight ];
    }
    else
    {
     size = [ document.getElementsByTagName('body')[0].clientWidth,
              document.getElementsByTagName('body')[0].clientHeight ];
    }

    return size;
   }
  </script>

  <style type = "text/css">
   body { border: 2px solid red; }
  </style>
 </head>

 <div id = "resizer"></div>
 <body onload = "init()">

  <input id = "debug" type = "text" size = "80" /><br />


  <button id = "btn" onclick = "grow()">Grow</button>
 </body>

</html>

The conept here is pretty simple. Like the technique used in the previous blog entry, once again we create a global reference to the previous viewport size (g_prevSize) when the page initially loads and then call setInterval(resize, 100); to monitor that viewport size at 100ms intervals.

In the resize(..) function itself, we determine the current viewport size (currentSize) and compare that against g_prevSize. If the width of currentSize (represented by index 0 in the array returned by the getViewportSize(..) function) is [i]different[/i] from the width of g_prevSize OR if the height of currentSize (represented by index 1) is different from the height of g_prevSize, then we know that the viewport size has changed, and hence, the window must have been resized.

Once we've determined that a resize has occurred, we simply update the value of g_prevSize and then go ahead with our resize logic.

If your resize logic is complicated and consists of many lines of code (or perhaps even if it doesn't) you may want to consider calling a separate function for it. In a real-world scenerio for example, after I determine that a resize needs to take place, I call a function, doResize(..).

I find this to be a bit cleaner than stuffing the resize detection and the resize logic all in one function.

So I think this is pretty straight-forward and not tremendously different from the technique used in my previous blog entry (though hopefully a bit more robust).

Comments welcome.

The javascript ternary operator

Pop Quiz: Do you understand the Javascript ternary operator?

You said "yes" didn't you? Alright hotshot. See if you can analyze these statements correctly:


var x = 'steve_' + 10 == 10 ? 'A' : 'B';
alert(x);

If you answered 'steve_A', you'd be wrong.

How about:


var y = 'steve_' + (10 == 10) ? 'C' : 'D';
alert(y);

You think the answer is 'steve_C'? Wrong again.

How about:


var z = 'steve_' + (10 == 10 ? 'E' : 'F');
alert(z);

'steve_E'? Ok, that one was easy.

But what about the first two examples? Why aren't they yielding the obvious answer? Read on to find out.

Continue reading The javascript ternary operator

Safely referencing objects in javascript (understanding null and undefined)

Part 1

Javascript is a finicky language. If you don't have an in-depth knowledge of the language specifications, some of the little nuances can really throw you off.

One area in particular where I've noticed a lot of confusion among javascript programmers is regarding the null and undefined types. In this article, I'm going to examine the difference between null and undefined (yes, there is a difference, subtle though it may be).

Then, I'm going to talk about what roll the null and undefined types play when trying to determine if it is safe to access a property or method of an object (or whether or not it is even safe to access the object itself).

Finally, I'm going to propose a solution for safety checking before attempting to access some object's properties or methods.

Let's get started!

Continue reading Safely referencing objects in javascript (understanding null and undefined)

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.

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