At the Forge - Unobtrusive JavaScript

 in
Remove JavaScript event handlers from HTML files using Prototype and Lowpro.

JavaScript has gone through a number of changes in the past few years. Implementations have become faster, more standardized and more stable. The development and growth of open-source JavaScript libraries, such as Prototype and Dojo, has helped mask many of the remaining differences between JavaScript implementations, such as with AJAX and event handling. The final change has occurred in the minds of developers (including myself), who now approach JavaScript as a serious application development language, rather than as a toy for highlighting images or doing simple effects.

Most JavaScript is executed not when it is initially read into a browser window, but rather when a particular event takes place. The easiest, and most common, way to assign event handlers is inside the HTML itself. For example, we can create a submit button for an HTML form as follows:


<form method="POST" action="/action">
    <input type="submit" value="Submit the form" />
</form>

When a user clicks on this button, the browser submits the contents of the form to the URL specified in the form tag's action attribute, using the method specified in the method attribute. But, we can change this by adding an onclick attribute to the submit button:


<form method="POST" action="/action">
    <input type="submit" value="Submit the form"
           onclick="alert('hello!'); return false;" />
</form>

With the onclick handler in place, the button now opens a JavaScript alert box (saying “hello”). Moreover, because our event-handler definition returns false, the form will not be submitted.

Of course, we don't have to put our JavaScript literally in the event handler. We could define a function somewhere else—in the document's <head> or perhaps in an external JavaScript file altogether:


<form method="POST" action="/action">
    <input type="submit" value="Submit the form"
           onclick="do_something(); return false;" />
</form>

Now, none of this is new. But, there are problems associated with setting event handlers in “on___” attributes. For one, it becomes difficult to assign more than one handler to the same event on an object.

A second and more significant reason is that our HTML becomes full of JavaScript. Until a few years ago, it wasn't unusual for HTML to be mixed in with code and style information as well, but the growth of strictly separated MVC frameworks have removed most code from the HTML, and style information now is put in external CSS files.

A growing movement during the past few years has pushed for “unobtrusive JavaScript”. Proponents of unobtrusive JavaScript argue that by placing JavaScript in a separate file and by defining event handlers in a separate file, the code becomes easier to read and understand and is cached by the browser. By using JavaScript unobtrusively, we also have the opportunity to make our HTML pages degrade gracefully, continuing to work with browsers that don't support JavaScript.

This month, we look at unobtrusive JavaScript and the unobtrusive approach to defining functions and event handlers. We also examine the Lowpro library that works with the popular Prototype JavaScript library, allowing us to write JavaScript that is unobtrusive, clean and easy to read.

Observing Events

Above, I showed how to assign a piece of JavaScript (called “do_something”) to an event on a particular HTML element. A fuller version of this HTML form, as well as some more content and tags, is shown in Listing 1 (test.html). This file contains a simple hyperlink, as well as our form.

I've already discussed how to handle an onclick event by setting the onclick attribute. However, there are at least two other methods for setting this event handler. One is to set the onclick attribute through JavaScript, treating onclick as a property of the DOM element associated with the hyperlink or button. Using Prototype's $() function, we can write:

$('hyperlink').onclick =
            function() { alert('clicked!'); return false; }

Notice how the event handler is an anonymous function, similar to “lambda” in Ruby and Python or an anonymous subroutine in Perl. The event-handling function can take an optional argument, whose value will be an event object. For example:

$('hyperlink').onclick =
            function(event) { alert(event); return false; }

With this alternate code in place, the alert (in Firefox, at least) indicates that the event was an “object MouseEvent”. This object, like all objects in JavaScript, then has a number of properties we can query. For example, the pageX and pageY properties indicate the X and Y coordinates of the mouse cursor when the event took place. We can see these by specifying the following:

$('hyperlink').onclick =
            function(event) { alert(event.pageX + ", " +
                              event.pageY); return false; }

Each click on the link will give a slightly different result, depending on the coordinates of the mouse cursor at the time of the click.

Of course, we also can define non-anonymous functions as our event handlers:

function show_x_and_y(event) {
    alert(event.pageX + ", " + event.pageY); return false;
}

$('hyperlink').onclick = show_x_and_y;

Notice that our assignment is to show_x_and_y (that is, the name of a function), rather than to show_x_and_y() (that is, the result of executing the function). This is a particularly useful technique if we want to assign the same function to handle multiple events.

We can handle a number of different events. For example, the onmouseover and onmouseout events let us execute a function based on when the mouse starts or stops pointing to a DOM element. Thus, we can do the following:

$('hyperlink').onmouseover =
            function() { $('the_form').hide(); }
$('hyperlink').onmouseout =
            function() { $('the_form').show(); }

When the mouse points to the hyperlink in test-2.html (Listing 2), the HTML form disappears. When the mouse moves away from the link, the form reappears. This might not be especially useful, but it does demonstrate the sorts of events (and event handlers) we can define.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

So interresting...

Arimbourg's picture

Thanks for this article. Clear and so usefull...

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix