|
Acknowledgment:
Kris Hadlock explains how to use design patterns for AJAX development to keep your applications scalable, reusable, and efficient.
Design patterns make development more efficient by speeding up common
programming processes and eliminating the need to write redundant code across
multiple projects. AJAX design patterns are emerging with the increased popularity of its use in Web application development. In this article, I’ll focus on a few patterns that are
specific to AJAX development.
This article assumes that you know the basics of AJAX, a server-side
technology, and are comfortable with basic database interactions. Although the
primary focus of this article is AJAX patterns, I’ll provide samples to
give you an idea of how to implement these patterns in your applications. All
the samples are available for download
here.
Before we focus on the patterns, let’s take a look at the standard web
application and AJAX models.
Standard Web Application Versus Standard AJAX Model
A standard web application begins with an HTTP request that’s triggered
by a user event. This request is sent to the server, resulting in a delay while
the server deals with the request appropriately and returns a new HTML page.
This can cause a disconnect between the user and the application because every
time the window refreshes the user has a delay in his experience. This is where
AJAX plays a very important role in the user experience.
AJAX provides an entirely different way of dealing with HTTP requests than
the standard web application model. Whereas the standard web application starts
with a user making a choice that sends a request to the server and returns a new
HTML page, the standard AJAX model does this without refreshing the page and
stopping the user experience to exchange data that the user shouldn’t
always have to be aware of in the first place. The standard AJAX model starts
with the user interface. A JavaScript event, which could be anything from a page
load to a button click, triggers an AJAX request and sets a callback method for
later use. AJAX makes an HTTP request to a server-side language, which queries
the database. On successful completion of the database interaction, the
server-side language responds to the callback method that was set during the
AJAX request with an XML or text response. The callback method typically does
some custom rendering or validation on the client side and writes the updated
data back into the user interface. The flow chart in Figure 1 shows the steps in
a standard AJAX model.
As an example for this article, I’m using an object-oriented AJAX
engine that I created to make requests more reusable. Following is an example of
the AJAX engine object:
document.write("<script type=\"text/javascript\"
src=\"js/HTTP.js\"></script>");
function Ajax()
{
this.toString = function() { return "Ajax"; }
this.http = new HTTP();
this.makeRequest = function(_method, _url, _callbackMethod)
{
this.request = (window.XMLHttpRequest)?
new XMLHttpRequest() :
new ActiveXObject("MSXML2.XMLHTTP");
this.request.onreadystatechange = _callbackMethod;
this.request.open(_method, _url, true);
this.request.send(_url);
}
this.checkReadyState = function(_id, _1, _2, _3)
{
switch(this.request.readyState)
{
case 1:
document.getElementById(_id).innerHTML = _1;
break;
case 2:
document.getElementById(_id).innerHTML = _2;
break;
case 3:
document.getElementById(_id).innerHTML = _3;
break;
case 4:
return this.http.status(this.request.status);
}
}
}
This AJAX object is extremely easy to use, as it only takes two lines of code
to make a request and one to check the readyState. First, you need to
instantiate the object and pass the method of request—the path to the file
that you’re requesting and a callback method to the makeRequest
method:
var ajax = new Ajax();
ajax.makeRequest(’GET’, ’xml/data.xml’, onResponse);
Once you write your callback method, you can check the ready state with the
checkReadyState method of the AJAX object:
function onResponse()
{
if(ajax.checkReadyState() == "success")
{
// add your parsing code here
}
}
As an addition to the AJAX object, I’ve created an HTTP object that
handles the status of the request and returns a value depending on the status
code. There are many more HTTP status codes to handle, but this example has the
most common:
function HTTP()
{
this.toString = function() { return "HTTP"; }
this.status = function(_status)
{
switch(_status)
{
case 200:
return "success";
break;
case 404:
return "File not found.";
break;
default:
return "HTTP Status: " + _status;
}
}
}
The standard AJAX model is very effective and aids in creating an intuitive
user experience, but there are specific situations that call for more advanced
data flow. The Data Reflection Pattern
The data reflection pattern keeps the page content in sync with the
database. It runs in the background and updates data that has changed while a
user is using the application. As the standard model does, the data reflection
pattern starts with the user interface, but the major difference is that it
programmatically consists of JavaScript’s setTimeout method. This
method continuously uses AJAX to call a server-side language and check for
database updates. If there are updates, the new data is returned to the AJAX
callback method and the page content is updated. The chart in Figure 2 shows the
flow of this pattern.
The setTimeout is the key difference in this pattern; it creates the
data reflection. Take a look at the code below to see how you can implement this
method into the AJAX object that we created in the standard AJAX model:
this.dataReflection = function(_delay, _callbackMethod)
{
setTimeout(_callbackMethod, _delay);
}
The dataReflection method accepts two parameters: the time delay in
milliseconds, and the callback method that will be called when the data is
received. Following is an example of how to make a request with the data
reflection method:
function get()
{
ajax.makeRequest(’POST’, ’services/post.php?method=get,
onResponse);
ajax.dataReflection(1000, get);
}
To reflect the data, the callback method will need a way of updating the
(X)HTML with the new content, if the content has been updated. For instance,
look at the following code and notice how the onResponse method checks
whether the date for a specific post has been updated:
var _date = null;
function onResponse()
{
if(ajax.checkReadyState() == "success")
{
var response = ajax.request.responseXML.documentElement;
if(_date != response.getElementsByTagName(
’date’)[0].firstChild.data)
{
// Add parsing code here
}
}
}
This makes the application run more efficiently because it eliminates
unnecessary content updates.
The data that’s returned contains a date element with a server-side
timestamp as its value. This pattern can be applied to a number of situations,
such as statistics or data representations that need to be updated continually.
The next pattern is an example of data reflection in a multiuser situation.
The Multiuser Pattern
The multiuser pattern is essentially an expanded version of the data
reflection pattern. It’s more robust because it creates an XML file that
can be called in a dataReflection method instead of continually calling
the database to check for new data. The chart in Figure 3 shows the flow of this
pattern.
Instead of returning the data, this pattern uses the server-side language to
create an XML file. The database data is concatenated into an XML structure and
written to this file for the data reflection method to request. In other words,
every time a user updates data, a new XML file is created on the server with the
updated data. Since the data reflection method is running in the background on
the client side, the new XML file is loaded on all users’ machines to
display the updated content.
The Object Return Pattern
The object return pattern is a standard AJAX/database interaction,
except that it returns an object in the form of HTML, XHTML, or XML. This
pattern is beneficial when you’re creating page content with an
object-oriented server-side language and need to create a new object and add it
to the page with the appropriate ID to be used for later access. The chart in
Figure 4 shows the flow of this pattern.
The example that’s included in the sample has a TextLink
class, which creates new hyperlinks in the database and assigns an ID and delete
button for removing each specific hyperlink.
Here’s an example of the TextLink class:
class TextLink
{
public function TextLink() {}
public function CreateLink($_id, $_string, $_url)
{
$link = "<a href=’" . $_url . "’ target=’_blank’
id=’" . $_id . "’>" . $_string . "</a>";
$deleteButton = ""nbsp;"nbsp;<a
href=\"javascript:deletePost(’$_id’);\">x</a><br/>";
return $link . $deleteButton;
}
}
The index page is nothing more than an HTML form with a div for
displaying hyperlinks:
<html>
<head>
<title>Object Return Pattern</title>
<script type="text/javascript" src="js/Ajax.js"></script>
<script type="text/javascript" src="js/request.js"></script>
</head>
<body onload="javascript:ajax.makeRequest(’POST’,
’services/post.php?method=get’, onResponse);">
<div id="body"></div>
<br/><br/>
<b>Add a new link</b>
<br/>
Name: <input id=’name’>
URL: <input id=’url’>
<input type=’button’ name=’submit’
value=’save this post’
onclick="javascript:saveNewLink();">
</body>
</html>
Once a name and a URL have been added and the submit button is clicked, the
saveNewLink method is triggered. This method posts the name and URL
value to the server-side language:
function saveNewLink()
{
var name = document.getElementById("name").value;
var url = document.getElementById("url").value;
ajax.makeRequest(’POST’,
"services/post.php?method=save"name="+
name +""url="+ url, onResponse);
}
The server-side language inserts the data into the database table and calls
the get method to return the updated XML:
public function save($id, $name, $url)
{
$this->dbConnect();
$query = "INSERT INTO $this->table (name, url)
VALUES (’$name’, ’$url’)";
$result = @mysql_query($query);
mysql_close();
$this->get();
}
The get method returns XML to the callback method of the original
AJAX request. What makes this response different is the fact that the
get method uses the TextLink object to create hyperlinks and
add them to the XML as HTML with the appropriate ID and delete button. Following
is the get method:
public function get()
{
$this->dbConnect();
$query = "SELECT * FROM $this->table ORDER BY id";
$result = mysql_db_query (DB_NAME, $query, LINK);
$xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
$xml .= "<links>\n";
while($row = mysql_fetch_array($result))
{
$textLink = new TextLink();
$xml .= "<link>\n";
$xml .= "<textLink><![CDATA[" .
$textLink->CreateLink(
$row[’id’],
$row[’name’],
$row[’url’]) . "]]></textLink>\n";
$xml .= "</link>\n";
}
$xml .= "</links>";
mysql_close();
header("Content-Type: application/xml; charset=UTF-8");
echo $xml;
}
Conclusion
Most developers are using design patterns every day to keep their
applications scalable, reusable, and efficient. With all the technology and
better user experience implementations, developers are bound to discover more
patterns. This is just part of an entirely new web experience—welcome to
Web 2.0.
|