Yahoo! User Interface library(YUI)

December 18, 2008

AJAX

«»

About Yahoo! User Interface Library – Book

Learning the Yahoo! User Interface Library introduces the popular open-source YUI JavaScript library and takes the user through each of the fully released components in detail looking at the classes that make up each component and the properties and methods that can be used. It includes a series of practical examples to reinforce how each component should/can be used. Author Dan Wellman takes the reader from beginner to advanced-level YUI usage and understanding.

What This Book Covers

In Chapter 1 we look at the library as a whole covering subjects such as how it can be
obtained, how it can be used, the structure and composition of it, and the license it has
been released under. We also look at a coding example featuring the Calendar control.

Chapter 2 covers the extensive CSS tools that come with the library, specifically the
Reset and Base tools, the Fonts tool, and the extremely capable Grids tool. Examples on
the use of each tool are covered.

In Chapter 3 we look at the all important DOM and Event utilities. These two
comprehensive utilities can often form the backbone of any modern web application and
are described in detail. We look at the differences between traditional and YUI methods
of DOM manipulation, and how the Event utility unites the conflicting Event models of
different browsers. Examples in this chapter include how the basic functions of the DOM
utility are used, and how custom events can be defined and subscribed to.

AJAX is the subject of Chapter 4, where we look in detail at how the Connection
Manager handles all of our XHR requirements. Examples include obtaining remote
data from external domains and the sending and receiving of data asynchronously to our
own servers.

Chapter 5 looks first at how the Animation utility can be used to add professional effects
to your web pages. It then moves on to cover how the Browser History Manager reenables
the back and forward buttons and bookmarking functionality of the browser when
used with dynamic web applications.

The Button family of controls and the TreeView control are the focus of Chapter 6. We
first cover each of the different buttons and look at examples of their use. We then
implement a TreeView control and investigate the methods and properties made available
by its classes.

In Chapter 7 we look at one of the most common parts of any web site—the navigation
structure. The example looks at the ease at which the Menu control can be implemented.
We also look at the AutoComplete control and create both array and XHR-based versions
of this component.

Chapter 8 looks at the container family of controls as well as the tabView control. Each
member of the container family is investigated and implemented in the coding examples.
The visually engaging and highly interactive TabView control is also looked at and
implemented.

Drag-and-Drop, one of DHTML‘s crowning acheivements is wrapped up in an easy to
use utility, forms the first part of Chapter 9. In the second part of this chapter we look
at the related Slider control and how this basic but useful control can be added to pages
with ease.

In Chapter 10 we cover the Logger control in detail and work through several examples
that include how the Logger is used to view the event execution of other controls and
how it can be used to debug existing controls and custom classes.

AJAX and Connection Manager

As far as web interface design techniques are concerned, AJAX is defi nitely the way to go. So what JavaScript library worth its salt these days wouldn’t want to include a component dedicated to this extremely useful and versatile method of client/server communication?

The term AJAX has been part of the mainstream development community’s vocabulary since early 2005 (with the advent of Google Mail). Although some of the key components that AJAX consists of, such as the XMLHttp object, have been around for much longer (almost a decade in fact). The goal of asynchronously loading additional data after a web page has rendered is also not a new concept or requirement.

Yet AJAX reinvented existing technologies as something new and exciting, and paved the way to a better, more attractive, and interactive web (sometimes referred to loosely as web 2.0) where web applications feel much more like desktop applications.

AJAX can also perhaps be viewed as the godfather of many modern JavaScript libraries. Maybe it wasn’t the sole motivating factor behind the growing plethora of available libraries, but it was certainly highly infl uential and orchestral in their creation and was at least partly responsible for the fi rst wave of modern, class-based JavaScript libraries.

Like many other cornerstone web techniques developed over the years, AJAX was (and still is) implemented in entirely different ways by different browsers. I don’t know if developers just fi nally had enough of dealing with these issues.

The very fi rst JavaScript libraries sprang into existence as a means of abstracting away the differences in AJAX implementation between platforms, thereby allowing developers to focus on the important things in web design instead of worrying about compatibility issues.

The result in many cases is a quick and easy way for developers to cut down on the amount of code they are required to produce, and a better more interactive experience for end users and website visitors.

The Connection Manager—A Special Introduction

The Connection Manager utility is by no means the smallest, most light-weight component included with the YUI, but it’s certainly not the largest either, yet it packs so much functionality into just 12Kb (for the –min version).

Connection Manager provides a fast and reliable means of accessing server-side resources, such as PHP or ASP scripts and handling the response. A series of supporting objects manage the different stages of any asynchronous transactions, whilst providing additional functionality where necessary.

Connection is one of just a few of the utilities that are supported by a single class; this makes looking up its methods nice and straight-forward. It also doesn’t have any properties at all (although the objects that it creates all have their own members which hold various pieces of information), which makes using it even easier!

This utility is what is known as a singleton utility, which means that there can only be one live instance of the utility at any one time, differing from many of the other components of the library. Don’t worry though, this doesn’t restrict you to only making one request; Connection will manage as many separate requests as you need.

Because this utility is a singleton, there are important considerations that advanced coders may want to take note of. Unlike some of the other library components, Connection cannot be subclassed—all of its class’s members are static, meaning that they won’t be picked up when using the YAHOO global .extend() method.

It wraps up the cross-browser creation of the XMLHttpRequest (XHR) object, as well as a simple to use object-based method of accessing the server response and any associated data, into a simple package which handles the request from start to finish. This requires minimal input from you, the developer, saving time as well as effort.

Another object created by Connection is the response object, which is created once the transaction has completed. The response object gives you access via its members to a rich set of data including the id of the transaction, the HTTP status code and status message, and either the responseText and responseXML members depending on the format of the data returned.

Like most of the other library components, Connection Manager provides a series of global custom events that can be used to hook into key moments during any transaction. We’ll look at these events in more detail later on in the chapter but rest assured, there are events marking the start and completion of transactions, as well as success, failure, and abort events.

The Connection utility has been a part of the YUI since its second public release (the 0.9.0 release) and has seen considerable bug fi xing and refi nement since this time. This makes it one of the more reliable and better documented utilities available.

Connection is such a useful utility that it’s used by several other library components in order to obtain data from remote sources. Other components that make use of Connection Manager include the AutoComplete control, DataTable, DataSource, and Tabview.

It is one of the only library components not dependant on the DOM utility. All it requires are the YAHOO global utility and the Event utility. That doesn’t mean that you can’t include a reference to the DOM utility, however, to make use of its excellent DOM manipulation convenience methods.

The XMLHttpRequest Object Interface

When working with the Connection utility you’ll never be required to manually create or access an XHR object directly. Instead, you talk to the utility and this works with the object for you using whichever code is appropriate for the browser in use. This means that you don’t need separate methods of creating an XHR object in order to keep each browser happy.

A transaction describes the complete process of making a request to the server and receiving and processing the response. Connection Manager handles transactions from beginning to end, providing different services at different points during a request.

Transactions are initiated using the .asyncRequest() method which acts as a constructor for the connection object. The method takes several arguments: the fi rst specifi es the HTTP method that the transaction should use, the second specifi es the URL of your server-side script while the third allows you to add a reference to a callback object.

A fourth, optional, argument can also be used to specify a POST message if the HTTP method is set to use POST giving you an easy means of sending data to the server as well as retrieving it. This is rarely required however, even when using the POST method, as we shall see later in the chapter.

It’s also very easy to build in query string parameters if these are required to obtain the data that you are making the request for. It can be hard coded into a variable and then passed in as the second argument of the Connection constructor instead of setting the second argument manually within the constructor.

Connection Manager takes these arguments and uses them to set up the XHR object that will be used for the transaction on your behalf. Once this has been done, and Connection has made the request, you then need to defi ne a new object yourself that will allow you to react to a range of responses from the server.

A Closer Look at the Response Object

I briefl y mentioned the response object that is created by the utility automatically once a transaction has completed, let’s now take a slightly more in-depth view at this object. It will be created after any transaction, whether or not it was considered a success.

The callback functions you defi ne to handle successful or failed transactions (which we’ll examine in more detail very shortly) are automatically passed to the response object as an argument. Accessing it is extremely easy and requires no additional intervention from yourself.

If the transaction fails, this object gives you access to the HTTP failure code and HTTP status message which are received from the server. Examining these two members of the response object can highlight what happened to make the request fail, making it integral to any Connection implementation.

If the transaction was a success, these two members will still be populated but with a success code and status message, and additional members such as responseText or responseXML will also contain data for you to manipulate.

If you need to obtain the HTTP response headers sent by the server as part of the response, these can be obtained using either the getResponseHeader collection, or the getAllResponseHeaders member.

In the case of fi le uploads, some of these members will not be available via the response object. File uploads are the one type of transaction that do not make use of the XHR object at all, so the HTTP code and status message members cannot be used. Similarly, there will not be either a textual or XML-based response when uploading files.

Managing the Response with a Callback Object

In order to successfully negotiate the response from the server, a literal callback object should be defi ned which allows you to deal quickly and easily with the information returned whether it is a success, failure, or another category of response.

Each member of this object invokes a callback function or performs some other action relevant to your implementation. These members can be one of several types including another object, a function call or even a string or integer depending on the requirements of your application.

The most common members you would use in your callback object would usually be based upon success and failure function calls to handle these basic response types, with each member calling its associated function when a particular HTTP response code is received by the response object.

It’s also very easy to add an additional member to this object which allows you to include data which may be useful when processing the response form the server. In this situation, the argument object member can be used and can take a string, a number, an object, or an array.

Other optional members include a customevents handler to deal with custom, pertransaction events as opposed to the global events that are available to any and all transactions, a scope object used to set the scope of your handler functions, and a timeout count used to set the wait time before Connection aborts the transaction and assumes failure.

The remaining member of the callback object is the upload handler which is of course a special handler to deal specifi cally with fi le uploads. As I already mentioned, the response object will be missing success of failure details when dealing with fi le uploads, however, you can still defi ne a callback function to be executed once the upload transaction has completed.

Working with responseXML

In this example we’re going to look at a common response type you may want to use—responseXML. We can build a simple news reader that reads headlines from a
remote XML fi le and displays them on the page.

We’ll also need an intermediary PHP fi le that will actually retrieve the XML file from the remote server and pass it back to the Connection Manager. Because of the
security restrictions placed upon all browsers we can’t use the XHR object to obtain the XML fi le directly because it resides on another domain.

This is not a problem for us however, because we can use the intermediary PHP fi le that we’re going to have to create anyway as a proxy. We’ll make requests from
the browser to the proxy thereby sidestepping any security issues, and the proxy will then make requests to the external domain’s server. The proxy used here in
this example is a cut down version of that created by Jason Levitt that I modified specifi cally for this example.

In order to complete this example you’ll need to use a full web server setup, with PHP installed and confi gured. Our proxy PHP fi le will also make use of the cURL
library, so this will also need to be installed on your server.

The installation of cURL varies depending on the platform in use, so full instructions for installing it is beyond the scope of this book, but don’t worry because there are
some excellent guides available online that explain this quick and simple procedure.

Even though Connection Manager only requires the YAHOO and Event utilities to function correctly, we can make use of some of the convenient functionality provided
by the DOM utility, so we will use the aggregated yahoo-dom-event.js instead of the individual YAHOO and Event fi les. We’ll also need connection-min.js and
fonts.css so make sure these are all present in your yui folder and begin with the following HTML:


	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
	<html lang="en">
	   <head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8">
		<title>Yui Connection Manager Example</title>
		<script type="text/javascript" src="images/2008/12/yahoo/yui/yahoo-dom-event.js"></script>
		<script type="text/javascript" src="images/2008/12/yahoo/yui/connection-min.js"></script>
		<link rel="stylesheet" type="text/css" href="yui/assets/fonts-min.css">
		<link rel="stylesheet" type="text/css" href="responseXML.css">
	   </head>
	   <body>
		<div id="newsreader">
		   <div class="header">Recent News</div>
		   <div id="newsitems"></div>
		   <div id="footer"><a class="link" href="http://news.bbc.co.uk/1/hi/ help/rss/4498287.stm">
							Copyright: © British
							Broadcasting Corporation</a></div>
		<div>
	   </body>
	</html>

We’ll start off with this very simple page which at this stage contains just the markup for the newsreader and the references to the required library fi les. There’s also a <link> to a custom stylesheet which we’ll create in a little while.

Adding the JavaScript

Directly after the final closing </div> tag, add the following <script>:</p>


	<script type="text/javascript">
	   //create namespace object for this example
	   YAHOO.namespace("yuibook.newsreader");
	   //define the initConnection function
	   YAHOO.yuibook.newsreader.initConnection = function() {
	     //define the AJAX success handler
	     var successHandler = function(o) {
		//define the arrays
		var titles = new Array();
		var descs = new Array();
		var links = new Array();

		//get a reference to the newsitems container
		var newsitems = document.getElementById("newsitems");

		//get the root of the XML doc
		var root = o.responseXML.documentElement;

		//get the elements from the doc we want
		var doctitles = root.getElementsByTagName("title");
		var docdescs = root.getElementsByTagName("description");
		var doclinks = root.getElementsByTagName("link");

		//map the collections into the arrays
		for (x = 0; x < doctitles.length; x++){
		   titles[x] = doctitles[x];
		   descs[x] = docdescs[x];
		   links[x] = doclinks[x];
		}
		//removed the unwanted items from the arrays
		titles.reverse();
		titles.pop();
		titles.pop();
		titles.reverse();
		descs.reverse();
		descs.pop();
		descs.reverse();
		links.reverse();
		links.pop();
		links.pop();
		links.reverse();

		//present the data from the arrays
		for (x = 0; x < 5; x++) {
		   //create new elements
		   var div = document.createElement("div");
		   var p1 = document.createElement("p");
		   var p2 = document.createElement("p");
		   var a = document.createElement("a");

		   //give classes to new elements for styling
		   YAHOO.util.Dom.addClass(p1, "title");
		   YAHOO.util.Dom.addClass(p2, "desc");
		   YAHOO.util.Dom.addClass(a, "newslink");

		   //create new text nodes and the link
		   var title = document.createTextNode(titles[x].firstChild.nodeValue);
		   var desc = document.createTextNode(descs[x].firstChild.nodeValue);
		   var link = links[x].firstChild.nodeValue;
		   a.setAttribute("href", link);

		   //add the new elements to the page
		   a.appendChild(desc);
		   p1.appendChild(title);
		   p2.appendChild(a);
		   div.appendChild(p1)
		   div.appendChild(p2)
		   newsitems.appendChild(div);
		}
	     }
	     //define the AJAX failure handler
	     var failureHandler = function(o) {
		//alert the status code and error text
		alert(o.status + " : " + o.statusText);
	     }
	     //define the callback object
	     var callback = {
		success:successHandler,
		failure:failureHandler
	     };
	     //initiate the transaction
	     var transaction = YAHOO.util.Connect.asyncRequest("GET", "myproxy.php", callback, null);
	   }
	   //execute initConnection when DOM is ready
	   YAHOO.util.Event.onDOMReady( YAHOO.yuibook.newsreader.initConnection);
	</script>

Once again, we can make use of the .onDOMReady() method to specify a callback function that is to be executed when the YUI detects that the DOM is ready, which is usually as soon as the page has fi nished loading.

The code within our master initialization function is split into distinct sections. We have our success and failure callback functions, as well as a callback object which will call either the success or failure function depending on the HTTP status code received following the request.

The failure handler code is very short; we can simply alert the HTTP status code and status message to the visitor. The callback object, held in the variable callback, is equally as simple, just containing references to the success and failure functions as values.

The pseudo-constructor which sets up the actual request using the .asyncRequest() method is just a single line of code, It’s arguments specify the response method (GET), the name of the PHP fi le that will process our request (myproxy.php), the name of our callback object (callback), and a null reference.

Connection Manager is able to accept URL query string parameters that are passed to the server-side script. Any parameters are passed using the fourth argument of the .asyncRequest() method and as we don’t need this feature in this implementation, we can simply pass in null instead.

Most of our program logic resides in the successHandler() function. The response object (o) is automatically passed to our callback handlers (both success and failure) and can be received simply by including it between brackets in the function declaration. Let’s break down what each part of our successHandler() function does.

We fi rst defi ne three arrays; they need to be proper arrays so that some useful array methods can be called on the items we extract from the remote XML fi le. It does make the code bigger, but means that we can get exactly the data we need, in the format that we want. We also grab the newsitems container from the DOM.

The root variable that we declare next allows us easy access to the root of the XML document, which for reference is a news feed from the BBC presented in RSS 2.0 format. The three variables following root allow us to strip out all of the elements we are interested in.

These three variables will end up as collections of elements, which are similar to arrays in almost every way except that array methods, such as the ones we need to use, cannot be called on the

email

«»

Comments

comments