July 18, 2019
Hot Topics:

Introducing Prototype and Scriptaculous Part 2

  • March 9, 2007
  • By Dave Crane and Bear Bibeault with Tom Locke
  • Send Email »
  • More Articles »
Adding event handlers

We go on to define an event handler for the entire widget ( in listing 1). This is an anonymous function, defined inline. Because of the way the JavaScript event model works, when the function is called, the variable this will no longer refer to the Rating object, but to the HTML element that fired the event. We refer to the variable rating, which is bound to the function as part of the closure, in order to see the Rating object inside the event-handling code.

It's a common mistake to refer to this inside event handlers, and writing this code took a few goes to straighten all the ratings and thises out, but we've done it. When the buttons are pressed, we re-render the entire UI by calling updateUI() again, this time with the delta argument to indicate that the rating is going up or down.

Finally, we tell the server that the rating for this item has changed . We'll be using core Ajax techniques to do this, and we'll look at these in a minute. First, let's review what we've done in order to get our two buttons up and running. We've visited a number of unusual language features in JavaScript, including the ability of Function objects to be called with arbitrary contexts (i.e., the variable that evaluates to this within the function), and the ability of Function objects to create closures implicitly. Both of these require quite a deep understanding of the language, which is fine if we like collecting unusual programming languages, but if we're a Java or PHP coder seconded into doing a bit of Ajax work, it's quite a lot to take on board.

We'll soon see how Prototype and Scriptaculous can help to keep the language out of our hair. First, let's have a look at the Ajax code.

Making an asynchronous HTTP call

We're going to use the XMLHttpRequest object to contact the server whenever the user clicks one of the buttons. As we noted earlier, XMLHttpRequest confers the ability to work with the HTTP protocol at quite a low level, and it is consequently not very straightforward to use for extremely simple tasks. There are several wrappers for the XMLHttpRequest available now, and we'll see the one provided by Prototype in a minute. To emphasize the difference, though, we're going to use the raw XMLHttpRequest in this example. Listing 2 shows the code required to do so.

Again, the code required to do the job isn't that small. Let's pick through the main points. First, we need to get hold of an XMLHttpRequest object. In some browsers it's a native object, and in others it's an ActiveX component, and we try to account for all the possibilities . By luck, we've got it the right way around here, testing for a native object first. Internet Explorer version 7 has arrived upon the scene, and it supports a native XMLHttpRequest, as well as ActiveX for backwards compatibility. If we'd tested for ActiveX first, we would have ended up using ActiveX unnecessarily under IE 7, and potentially blocking browsers where ActiveX controls have been locked down, but our Ajax code would otherwise have worked. We could have supported older versions of IE by checking for alternative ActiveX types too, but that's a lot of background knowledge required to implement a simple rating widget, so users of IE 5.5 are maybe out of luck with our app.

The second point to note is that strange closure trick again. We define the variable rating and then refer to it inside the event handler . In this case, the event handler is simply a one-line call to another function, which might leave us wondering why the onReadyState() function wasn't assigned directly if we didn't understand the intricacies of implicit closures in JavaScript.

We're calling a server-side process that talks in terms of standard querystring key-value pairs. Almost every server-side language provides automatic parsing of querystrings, but with XMLHttpRequest, we need to build up the string manually , remembering to call encodeURI() for each value. We then need to set a few crucial HTTP headers before we're ready to send our request out . It's a little-known fact that the convenience methods we're used to on the server, such as Java Servlet's request.getParameter() and PHP's $_GET array, will only be populated if the request has a content type of application/x-www-form-urlencoded. HTML forms fill this in for us automatically, but with XMLHttpRequest, we need to do it ourselves.

Once the request goes out, our callback handler is busy. Rather than being called once when the request completes, it is notified at various stages in the lifecycle of the request, which is great for implementing progress bars, but something of an overhead for us here. A readystate value of 4 corresponds to a completed request, so we simply check for that and then call either the success handler or the error handler depending on the HTTP code of our response.

Let's review what we've been through here. Once more, everything is done, and it works, but we've gone to rather a lot of effort, and we've needed rather an intimate knowledge of the HTTP protocol, particularly concerning how querystrings are encoded in requests and are only decoded on the server if the right set of HTTP headers is applied. Furthermore, we've had to get our heads around closures once again. After writing this application, I refactored the code to use Prototype and Scriptaculous features in a few places, to make it easier to work with. Let's look at how it simplified things.

Page 2 of 4

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date