It’s easy to think of the ASP.NET AJAX framework primarily in terms of the server controls it provides. However, make sure that you don’t overlook the client script helper classes at your disposal. Many of them are very useful and surprisingly powerful.

In the next several posts, I’ll be examining these client side helper classes and hopefully giving you some ideas for more effectively using them.

In this first post, I’m going to take a closer look at $addHandler.


$addHandler’s functionality and syntax

$addHandler is a static, shortcut function for Sys.UI.DomEvent.addHandler. It allows you to attach a client side event handler to any DOM element on your page. You have probably seen it before, but might be surprised by how much power and flexibility it offers just under the surface.

Its syntax is as follows:

Sys.UI.DomEvent.addHandler(element, eventName, handler);

Element accepts a DOM element. This argument is most often provided by using $get() or getElementById(). However, any valid reference to a DOM element may be used.

EventName accepts a string specifying which event you want to handle. It expects a standard DOM event name with the “on” prefix removed. For example, use “click” to handle onclick and use “focus” to handle onfocus.

Handler accepts a reference to the JavaScript function that should be called for this event. On event, this handler function will be called with a single argument of type Sys.UI.DomEvent.

Example #1: That pesky enter key.

The enter key tends to bring considerable nuisance to ASP.NET forms. DefaultButton has helped ease that pain somewhat, but submitting the form isn’t always what the user wants to do when they press enter.

Instead of helping the user accidentally submit a half-completed form, we can easily use $addHandler to intercept the enter key and prevent the form submission altogether.

$addHandler($get('TextBox1'), 'keydown', TextBox1_KeyDown);
 
function TextBox1_KeyDown(evt) {
  // Check to see if it's the enter key that raised
  //  the keydown event.
  if (evt.charCode == Sys.UI.Key.enter) {
    // This prevents the form submission.
    evt.preventDefault();
 
    // Focus the next TextBox instead, similar
    //  to the behavior expected from tab.
    $get('TextBox2').focus();
  }
}

This calls the TextBox1_KeyDown client side function on every key press, as long as TextBox1 is focused. If the key press is the enter key, preventDefault() is called to prevent the form submission that would normally occur. Finally, the next form field is focused.

From the user’s point of view, the enter key functions just like the tab key.

Preferably, you would use more generic code for focusing the next form field and then add the same handler to all but the last form field. The code to do that is beyond the scope of this post, but is readily available via Google.

Example #2: I hit the tab key because I wanted a tab!

Something that has always annoyed me about most textarea input fields on websites is that the tab key switches focus to the next form fields, instead of inserting a tab character. In fact, even the textarea I’m using to write this very post has that infuriating behavior.

This is how you could use $addHandler to fix that:

$addHandler($get('MultiLineTextBox1'), 'keydown', TabExpander);
 
function TabExpander(evt) {
  // If a tab is received, then insert a tab character
  //  in the HTML element that raised the event.
  if (evt.charCode == Sys.UI.Key.tab) {
    evt.preventDefault();
    // Code here to insert a \t in evt.target, which is 
    //  long, messy, and omitted for brevity.
  }
}

Note the use of Sys.UI.Key in this and the previous example. Key is an enumeration of the ASCII key codes corresponding to various special keys, such as enter, ctrl, shift, delete, etc. Sys.UI.Key.enter evaluates to 13, Sys.UI.Key.tab to 9, and so on.

It’s a bit more typing, but I think the drastic readability improvement is well worth it. For a complete list of Key members, see the Sys.UI.Key documentation.

Example #3: Oops, does this thing have an undo button?

Any application with delete capability inevitably incurs all too many accidental deletions. Sure, you can use a confirmation dialog, but your average user is well conditioned to find the “ok” button and click it as quickly as possible.

How about requiring an unusual gesture to activate the delete function? For this example, let’s use ctrl + click. That’s pretty tough to do accidentally.

$addHandler($get('DeleteButton'), 'click', DeleteHandler);
 
function DeleteHandler(evt) {
  // If the ctrl key was being pressed when the
  //  the click happened, then proceed.
  if (evt.ctrlKey)
    evt.target.value = 'Deleting...';
 
  // Else, use preventDefault to abort the click
  //  and let the user know that they've failed.
  else {
    evt.preventDefault();
    evt.target.value = 'No secret handshake, no delete.';
  }
}

Evt.target provides a reference to the DOM object that raised the event. So, in the case of this button, using evt.target.value changes the button’s text. This flexibility opens up nearly unlimited potential for rich UI functionality, with relatively minimal work on our part.

Conclusion

Instead of learning to use $addHandler, you might consider wiring events up by using direct assignment (as seen in tutorials on many popular sites). However, it’s important to understand that doing so will overwrite existing handlers for that element/event combination. Do that throughout your code and you will quickly end up in a situation where debugging is tedious at best.

Additionally, the DomEvent class that $addHandler provides your handler function is a great tool. For example, its charCode property does a great job of abstracting cross-browser key code support. To do this by hand, you would need several more lines of code. It’s often the little things that make your code maintainable, and this is one of them.

If you’re already using ASP.NET AJAX anyway, I think using $addHandler for your client side event wireups is definitely a best practice.