Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ajax In Action (2006).pdf
Скачиваний:
63
Добавлен:
17.08.2013
Размер:
8.36 Mб
Скачать

Third-party libraries and frameworks

103

 

 

basically the same, and this is how MVC is generally understood in the web application world.

Describing our web architecture using MVC is a useful approach, and it will continue to serve us well as we move from classic to Ajax-style applications. But it isn’t the only use to which we can put MVC in Ajax. In chapter 4, we will examine a variation on the pattern that allows us to reap the advantages of structured design throughout our application. Before we do that, though, let’s look at another way of introducing order to our Ajax applications.

As well as refactoring our own code, we can often rationalize a body of code by making use of third-party frameworks and libraries. With the growing interest in Ajax, a number of useful frameworks are emerging, and we conclude this chapter with a brief review of some of the more popular ones.

3.5 Third-party libraries and frameworks

A goal of most refactoring is reducing the amount of repetition in the codebase, by factoring details out to a common function or object. If we take this to its logical conclusion, we can wrap up common functionality into libraries, or frameworks, that can be reused across projects. This reduces the amount of custom coding needed for a project and increases productivity. Further, because the library code has already been tested in previous projects, the quality can be expected to be high.

We’ll develop a few small JavaScript frameworks in this book that you can reuse in your own projects. There’s the ObjectBrowser in chapters 4 and 5, the CommandQueue in chapter 5, the notifications frameworks in chapter 6, the StopWatch profiling tools in chapter 8, and the debugging console in appendix A. We’ll also be refactoring the teaching examples in chapters 9 through 13 at the end of each chapter, to provide reusable components.

Of course, we aren’t the only people playing this game, and plenty of JavaScript and Ajax frameworks are available on the Internet, too. The more established of these have the advantage of some very thorough testing by a large pool of developers.

In this section, we’ll look at some of the third-party libraries and frameworks available to the Ajax community. There’s a lot of activity in the Ajax framework space at the moment, so we can’t cover all the contenders in detail, but we’ll try to provide you with a taste of what sort of frameworks exist and how you can introduce order into your own projects by using them.

104CHAPTER 3

Introducing order to Ajax

3.5.1Cross-browser libraries

As we noted in section 3.2.1, cross-browser inconsistencies are never far away when writing Ajax applications. A number of libraries fulfill the very useful function of papering over cross-browser inconsistencies by providing a common façade against which the developer can code. Some focus on specific pieces of functionality, and others attempt to provide a more comprehensive programming environment. We list below the libraries of this type that we have found to be helpful when writing Ajax code.

x library

The x library is a mature, general-purpose library for writing DHTML applications. First released in 2001, it superseded the author’s previous CBE (CrossBrowser Extensions) library, using a much simpler programming style. It provides cross-browser functions for manipulating and styling DOM elements, working with the browser event model, and includes out-of-the-box support libraries for animation and drag and drop. It supports Internet Explorer version 4 upward, as well as recent versions of Opera and the Mozilla browsers.

x uses a simple function-based coding style, taking advantage of JavaScript’s variable argument lists and loose typing. For example, it wraps the common document.getElementById() method, which accepts only strings as input, with a function that accepts either strings or DOM elements, resolving the element ID if a string is passed in but returning a DOM element unmodified if that is passed in as argument. Hence, xGetElementById() can be called to ensure that an argument has been resolved from ID to DOM node, without having to test whether it’s already been resolved. Being able to substitute a DOM element for its text ID is particularly useful when creating dynamically generated code, such as when passing a string to the setTimeout() method or to a callback handler.

A similarly concise style is used in the methods for manipulating DOM element styling, with the same function acting as both getter and setter. For example, the statement

xWidth(myElement)

will return the width of the DOM element myElement, where myElement is either a DOM element or the ID of a DOM element. By adding an extra argument, like so

xWidth(myElement,420)

we set the width of the element. Hence, to set the width of one element equal to another, we can write

Third-party libraries and frameworks

105

 

 

xWidth(secondElement,xWidth(firstElement))

x does not contain any code for creating network requests, but it is nonetheless a useful library for constructing the user interfaces for Ajax applications, written in a clear, understandable style.

Sarissa

Sarissa is a more targeted library than x, and is concerned chiefly with XML manipulation in JavaScript. It supports Internet Explorer’s MSXML ActiveX components (version 3 and up), Mozilla, Opera, Konqueror, and Safari for basic functionality, although some of the more advanced features such as XPath and XSLT are supported by a smaller range of browsers.

The most important piece of functionality for Ajax developers is cross-browser support for the XMLHttpRequest object. Rather than creating a Façade object of its own, Sarissa uses the Adapter pattern to create a JavaScript-based XML- HttpRequest object on browsers that don’t offer a native object by that name (chiefly Internet Explorer). Internally, this object will make use of the ActiveX objects that we described in chapter 2, but as far as the developer is concerned, the following code will work on any browser once Sarissa has been imported:

var xhr = new XMLHttpRequest(); xhr.open("GET", "myData.xml"); xhr.onreadystatechange = function(){

if(xhr.readyState == 4){ alert(xhr.responseXML);

}

}

xhr.send(null);

Compare this code with listing 2.11 and note that the API calls are identical to those of the native XMLHttpRequest object provided by Mozilla and Safari browsers.

As noted already, Sarissa also provides a number of generic support mechanisms for working with XML documents, such as the ability to serialize arbitrary JavaScript objects to XML. These mechanisms can be useful in processing the XML documents returned from an Ajax request to the server, if your project uses XML as the markup for response data. (We discuss this issue, and the alternatives, in chapter 5.)

Prototype

Prototype is a general-purpose helper library for JavaScript programming, with an emphasis on extending the JavaScript language itself to support a more object-oriented programming style. Prototype has a distinctive style of JavaScript

106CHAPTER 3

Introducing order to Ajax

coding, based on these added language features. Although the Prototype code itself can be difficult to read, being far removed from the Java/C# style, using Prototype, and libraries built on top of it, is straightforward. Prototype can be thought of a library for library developers. Ajax application writers are more likely to use libraries built on top of Prototype than to use Prototype itself. We’ll look at some of these libraries in the following sections. In the meantime, a brief discussion of Prototype’s core features will help introduce its style of coding and will be useful when we discuss Scriptaculous, Rico, and Ruby on Rails.

Prototype allows one object to “extend” another by copying all of the parent object’s properties and methods to the child. This feature is best illustrated by an example. Let’s say that we define a parent class Vehicle

function Vehicle(numWheels,maxSpeed){ this.numWheels=numWheels; this.maxSpeed=maxSpeed;

}

for which we want to define a specific instance that represents a passenger train. In our child class we also want to represent the number of carriages and provide a mechanism for adding and removing them. In ordinary JavaScript, we could write

var passTrain=new Vehicle(24,100); passTrain.carriageCount=12; passTrain.addCarriage=function(){

this.carriageCount++;

}

passTrain.removeCarriage=function(){ this.carriageCount--;

}

This provides the required functionality for our passTrain object. Looking at the code from a design perspective, though, it does little to wrap up the extended functionality into a coherent unit. Prototype can help us here, by allowing us to define the extended behavior as an object and then extend the base object with it. First, we define the extended functionality as an object:

function CarriagePuller(carriageCount){ this.carriageCount=carriageCount; this.addCarriage=function(){

this.carriageCount++;

}

this.removeCarriage=function(){ this.carriageCount--;

}

}

Third-party libraries and frameworks

107

 

 

Then we merge the two to provide a single object containing all of the required behavior:

var parent=new Vehicle(24,100);

var extension=new CarriagePuller(12);

var passTrain=Object.extend(parent,extension);

Note that we define the parent and extension objects separately at first and then mix them together. The parent-child relationship exists between these instances, not between the Vehicle and CarriagePuller classes. While it isn’t exactly classic object orientation, it allows us to keep all the code related to a specific function, in this case pulling carriages, in one place, from which it can easily be reused. While doing so in a small example like this may seem unnecessary, in larger projects, encapsulating functionality in such a way is extremely helpful.

Prototype also provides Ajax support in the form of an Ajax object that can resolve a cross-browser XMLHttpRequest object. Ajax is extended by the Ajax.Request type, which can make requests to the server using XMLHttpRequest, like so:

var req=new Ajax.Request('myData.xml');

The constructor uses a style that we’ll also see in many of the Prototype-based libraries. It takes an associative array as an optional argument, allowing a wide range of options to be configured as needed. Sensible default values are provided for each option, so we need only pass in those objects that we want to override. In the case of the Ajax.Request constructor, the options array allows post data, request parameters, HTTP methods, and callback handlers to be defined. A more customized invocation of Ajax.Request might look like this:

var req=new Ajax.Request( 'myData.xml',

{

method: 'get',

parameters: { name:'dave',likes:'chocolate,rhubarb' }, onLoaded: function(){ alert('loaded!'); }, onComplete: function(){

alert('done!\n\n'+req.transport.responseText);

}

}

);

The options array here has passed in four parameters. The HTTP method is set to get, because Prototype will default to the HTTP post method. The parameters array will be passed down on the querystring, because we are using HTTP get. If we used POST, it would be passed in the request body. onLoaded and onComplete are