At the Forge - Prototype

Prototype eases the burden of using JavaScript in Ajax.

During the last few months, we have looked at ways to use JavaScript, a version of which is included in nearly every modern Web browser. For most of its life, JavaScript has been used to create simple client-side effects and actions on Web pages. But during the past year or two, JavaScript has taken center stage as part of the Ajax (Asynchronous JavaScript and XML) paradigm. It is no longer enough to create Web applications that reside on the server. Modern Web applications must include Ajax-style behavior, which probably means integrating JavaScript into the mix of server-side programs, HTML and relational databases.

As we have seen in the last few installments of this column, however, using JavaScript requires a fair amount of repeated code. How many times must I invoke document.getElementById(), just to grab nodes that I want to modify? Why must I create a library that handles the basic Ajax calls that I will be making on a regular basis? Must I create all of my own widgets and graphic effects?

Fortunately for Web developers everywhere, the explosive interest in Ajax has led to equally productive work on libraries to answer these questions and needs. Many of these libraries have been released under open-source licenses and are thus available for Web developers to include in a variety of different types of sites.

This month, we look at one of the best-known JavaScript libraries, known as Prototype. Prototype, developed by Sam Stephenson (a member of the Ruby on Rails core team), has been included in all copies of Ruby on Rails for some time. Prototype aims to make it easier to work with JavaScript, offering a number of shortcuts for some of the most common uses.

Getting and Using Prototype

If you are using Ruby on Rails for your Web applications, Prototype is already included. You can begin to use it in your applications by adding the following inside a Rails view template:

<%= javascript_include_tag 'prototype' %>

If you are not using Rails, you still can use Prototype. Simply download it from its site (see the on-line Resources). Then use:

<script type="text/javascript" src="/javascript/prototype.js"></script>

The above assumes, of course, that you have put prototype.js in the /javascript URL on your Web server. You might have to adjust that URL to reflect the configuration of your system.

Once you have included Prototype, you can start to take advantage of its functionality right away. For example, Listing 1 shows simpletext.html. This file contains some simple JavaScript that changes the headline to the contents of the text field when you click on the submit button.

We do this by defining a function (setHeadline) and then by setting that function to be invoked when we click on the button:

<p><input type="button" value="Change headline"

Now, what happens inside setHeadline? First, we grab the node containing the headline:

var headline = document.getElementById("headline");

Then, we get the contents of the text field, which we have called field1:

var fieldContents = document.forms[0].field1.value;

Notice how we must grab the value by going through the document hierarchy. First, we get the array of forms from the document (document.forms), then we grab the first form (forms[0]), then we grab the text field (field1), and then we finally get the value.

Now we can set the value of the headline by attaching a text node to the h2 node. We do this with a function called setText, which I have included in simpletext.html; setText depends in turn on removeText and appendText, two other helper functions that make it easy to work with text nodes in JavaScript.

All of this is very nice and is typical of the type of JavaScript coding I often do. How can Prototype help us? By simplifying our code using two built-in functions. The first, $(), looks a bit strange but is legitimate—its full name is $ (dollar sign), and it performs much the same task as document.getElementById, returning the node whose ID matches its parameter. The second, $F, returns the value from the form element whose ID matches the parameter.

In other words, we can rewrite our function as:

function setHeadline() {
var headline = $("headline");
var fieldContents = $F("field1");
setText(headline, fieldContents);

Sure enough, this works just as well as the previous version. However, it's a bit easier to read (in my opinion), and it allows us to avoid traversing the document hierarchy until we reach the form element.

We can improve our code even further by removing our setText, updateText and removeText functions, all of which were included simply because JavaScript doesn't provide any easy way to manipulate the text of a node. But Prototype does through its Element class, allowing us to rewrite setHeadline as:

function setHeadline() {
    Element.update($("headline"), $F("field1"));

The code invokes Element.update, handing it two parameters: the node whose text we want to modify and the text we want to insert in place of the current text. We have just replaced 30 lines of our code with one line, thanks to Prototype. You can see the result in Listing 2.