 | Level: Introductory Brian J. Dillard (bdillard@pathf.com), RIA Evangelist, Pathfinder Development
04 Mar 2008 This first article in a series on overhauling existing sites with
Asynchronous JavaScript + XML (Ajax) shows you how to eliminate pop-up windows and
navigational dead-ends with simple modal windows.
Ajax techniques have changed the face of large, commercial Web applications, but many
smaller Web sites don't have the resources to rebuild their entire user interfaces
(UIs) overnight. New features should justify their cost by solving real-world interface
problems and improving the user experience. This article shows how you can eliminate
pop-up windows and navigational dead-ends with simple modal windows. By using the
principle of progressive enhancement, you can guarantee that such advanced UI
features don't hamper your site's accessibility and adherence to Web standards.
This article assumes you have a solid grasp of Hypertext Markup Language (HTML) and Cascading
Style Sheet (CSS) and at least a basic understanding of JavaScript programming and
Ajax. The sample application is built using only client-side code; the techniques
demonstrated could be adapted to any server-side application framework. To run the
example site, you need at least a basic Web server running on localhost. Alternatively,
you can just follow along in the source code and see the example site in action on my
Web server (see Resources for a link).
Introducing the concept: Retrofitting your site with Ajax
The need to guide your users down a specific path—say, from product search
to checkout—is as old as the Web itself. Yet it's fraught with danger: the
danger of losing your users along the way. The longer and more complex your
navigational path, the more places for users to bail. You need to present
those users with enough information to keep them interested in the process at hand.
 |
The task at hand
This article walks you through the steps of retrofitting a Web 1.0 shopping site
with Ajax techniques. The "before" and "after" source code for the example
application is available from the Download section.
You can also see both versions in action on my Web server (see
Resources). In addition to Ajax techniques and best
practices, you learn how Ajax can improve your user experience through principles
of progressive enhancement.
Wikipedia defines progressive enhancement as a strategy for Web design that emphasizes accessibility, semantic markup, and external stylesheet and scripting technologies. Progressive enhancement uses Web technologies in a layered fashion that allows everyone to access the basic content and functionality of a Web page, using any browser or Internet connection, while also providing those with better bandwidth or more advanced browser software an enhanced version of the page.
|
|
In the Web 1.0 world, shopping sites streamlined their user experience by
constructing a straight path from search and results through selection and purchase.
Whenever users wanted more information than the purchase path could provide, they
had to take a navigational detour to an information-rich product details or
comparison page. The problem with these "side streets" is that they take users
out of the purchase path and give them more chances to abandon the process.
They're also difficult to maintain because your navigation logic has to store
information about how a user got to this cul-de-sac.
Pop-up windows seemed to offer a solution. With supplemental information relegated
to pop-ups, the straight, step-by-step path could continue uninterrupted in the
main window. Unfortunately, however, pop-up windows are confusing and annoying.
They may be easier to maintain than navigational side streets, but they're just as
likely to take your users out of the process you want them to complete.
Luckily, open source JavaScript libraries offer an easy way to get rid of side
streets and pop-ups once and for all. This article demonstrates how to use Ajax and
Dynamic HTML (DHTML) techniques to render your supplemental information inside
tooltips, lightboxes, and other modal windows. Because these elements can be
inserted on-the-fly into any page, they help preserve the quick, step-by-step path
from home page to purchase.
Introducing the application: Customize Me Now
The example application in this article focuses on e-commerce. I've constructed an
imaginary shopping application called Customize Me Now that allows users to
personalize and purchase an array of disparate products: a pizza, a vacation
package, or an investment portfolio. In real life, of course, these product
categories would never live on the same site. But together, they demonstrate the
kind of complex, real-world navigational challenges many sites face.
By presenting a Web 1.0 version of Customize Me Now, and then retrofitting it into
a Web 2.0 version, you can see just how streamlined your navigational funnel can
become when you know that supplemental information is only a single Ajax call away.
The techniques covered here can be adapted to any process where the need for
simplicity competes with the need to educate users. Configuring a product, taking a
survey, signing up for a bundle of services, or simply completing a registration
form—all these processes can be streamlined with Ajax.
Introducing the techniques: Ajax, tooltips, modal windows, and
lightboxes
By now, Ajax probably needs no introduction: It has become so ubiquitous in the
Web-development world that it has lost its all-caps status. For years now, savvy
programmers have been using JavaScript code to update Web pages incrementally,
without a round-trip to the server. But it was only with the adoption of the
xmlHttpRequest object—originally a Windows®
Internet Explorer® extension but now supported across a wide variety of
browsers—that Ajax went mainstream. Anytime you use a Web application that
feels more like a desktop application, chances are you're seeing Ajax in action.
This article doesn't go into the basics of Ajax programming, but you will be using
many open source libraries that use Ajax techniques.
Ajax UIs often employ tooltips, lightboxes, and modal windows. These are all just
fancy names for pop-up screens that appear within a browser viewport rather than
being launched in a separate window. Tooltips are typically small windows
that provide contextual content, usually when the user hovers over a trigger
element. Modal windows are typically larger and usually triggered by a
click event. Lightboxes are a specific kind of modal window in which a
translucent overlay separates the window's original content from the modal
content. Any of these containers can be filled with a variety of content: inline
content that's been hidden with DHTML techniques; new content pulled from the
server by an Ajax call; or entirely separate documents pulled into an iframe.
Netflix, the popular DVD rental service, provides a compelling example of these
interface elements in action.
Introducing the tools: jQuery, GreyBox, ThickBox, JTip, and
jQuery forms
Open source JavaScript toolkits have multiplied since Ajax went
mainstream in 2005. Each has its strengths, weaknesses, and quirks, but the best
ones paper over browser differences and provide an elegant, cross-browser
application program interface (API) for Ajax, DHTML, and visual effects. Some
solutions, such as the Google Web Toolkit, use server-side Java™ code to
generate client-side JavaScript code automatically. Most, however, are native
JavaScript libraries.
You're going to work with one such library, jQuery, whose elegant API and philosophy
of unobtrusive JavaScript have earned it an enthusiastic following since its
2006 debut. Using jQuery, you can take an existing, Ajax-free Web 1.0 Web site and
turn it into an Ajax-powered Web 2.0 site with almost no changes to the server
code, the HTML markup, or the CSS. Your JavaScript code will transform existing
HTML elements and behaviors at run time within the browser. If JavaScript is
disabled or the browser doesn't support it, the markup will still work the way it
always did. This progressive enhancement principle ensures that
your Web applications remain accessible to the broadest possible range of users.
Mobile devices, assistive software for the physically impaired, or even decade-old
Web browsers: All will still be able to run your application.
In addition to its support for progressive enhancement, jQuery allows you to
leverage a large, vibrant community of plug-in developers. Many JavaScript toolkits
attempt to anticipate every possible developer need, but jQuery focuses on the
basics. The core library remains light, while additional capabilities are delivered
as plug-ins by the open source community. Specifically, you'll employ the following
plug-ins:
-
ThickBox: Developed by Cody Lindley
-
jQuery Forms: A collaborative effort of the jQuery community
-
JTip: Developed by Cody Lindley and extended by the jQuery community
-
GreyBox: Developed by Amir Salihefendic
Understanding the application: Customize Me Now 1.0
The following sections help you familiarize yourself with Customize Me Now 1.0 — its user
experience and its source code.
The user experience
Figure 1 shows the Customize Me Now Results page and an
informational pop-up window. It demonstrates how much information the site
offers users about the products they're customizing. Although the optimal user
path is a straight line from search and results to customization and purchase,
the interface offers several detours from this route. The site uses traditional
pop-up windows to present small chunks of contextual information about each
product and product option. Click Pizza, and you see information about
the site's pizza product. Click Cheese, and you see information about
the available cheeses for your pizza. In addition, users can navigate to the
manufacturer's Web site—also rendered in a pop-up
window.
Figure 1. The Results page 1.0
If users want to get even more details, the site offers a Product Details
page with far more information about each product -- pictures, articles, user
reviews, and so on. Finally, if users want to see how individual products
stack up against one another, they can view them side-by-side on the
Comparison page. Navigation among all these resources is complex. Because users
need to customize each product, it's hard simply to offer an Add to cart
link at each step of the way. The site encourages users to customize, then add
to cart. But it also offers the ability to flip those steps by adding to cart
with a set of default options, then customizing later.
Figure 2 provides a wireframe site map of Customize Me Now
1.0. It demonstrates just how convoluted a user's path can become. Most screens
link to at least two or three other screens.
Figure 2. Customize Me
Now 1.0 site map
The code
The functional demo code for Customize Me Now provides just the client-side
assets: HTML CSS, JavaScript code, and image files. In the real world, you would
obviously have a large server-side component, too: Microsoft® ASP.NET,
Java technology, Ruby on Rails, Django, or PHP. But the beauty of jQuery is
that it's completely client-side. You can simplify your user experience using
Ajax techniques without having to mess with your server components. I haven't
provided any server-side code because those details don't matter for the
project at hand. Just know that whenever you open an HTML file, it could easily
be a PHP template, a JavaServer Pages™ (JSP) file, or any other file
that sends HTML to the browser.
After you've downloaded the source code for the version 1.0 application, look at
the markup for one of your pages. It should look like
Listing 1.
Listing 1. HTML code for results.html 1.0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Customize Me Now: Search Results</title>
<link rel="stylesheet" type="text/css" href="../css/customizemenow.css"/>
</head>
<body id="CMN">
<!--[header goes here]-->
<div id="main">
<form method="GET" action="comparison.html">
<h1>Search Results</h1>
<div class="buttons">
<input class="button" type="submit" name="submitTop" id="submitTop"
value="Compare Selected Products" />
or <a href="index.html">search again</a>
</div>
<table class="searchResults">
<thead>
<tr>
<th>Product</th>
<th>Description</th>
<th>Options</th>
<th>Compare</th>
<th>Actions</th>
</tr>
</thead>
<tr>
<td class="name">
<a target="productPopup"
href="productPopup.html?product=A">Pizza</a>
</td>
<td class="desc">
A delicious Italian treat.<br />
[<a href="detail.html?product=A">full product details</a>]
</td>
<td class="options">
<ul>
<li>
<a target="optionsPopup"
href="optionsPopup.html?product=A">crust</a>
</li>
<li>
<a target="optionsPopup"
href="optionsPopup.html?product=A">cheese</a>
</li>
<li>
<a target="optionsPopup"
href="optionsPopup.html?product=A">toppings</a>
</li>
</ul>
</td>
<td class="action">
<input type="checkbox" target="productPopup" name="compareA"
id="compareA" value="true" checked="checked"/>
</td>
<td class="action">
<a class="button" href="customize.html?product=A">customize
product</a>
<a class="button" href="cart.html?product=A">add to cart with
default options</a>
</td>
</tr>
<!--[additional table rows go here]-->
</table>
<div>
<div class="buttons">
<input class="button" type="submit" name="submitBottom" id="submitBottom"
value="Compare Selected Products" />
or <a href="index.html">search again</a>
</div>
</form>
</div>
<!--[footer goes here]-->
</body>
</html>
|
Retrofitting the application
The process of retrofitting Customize Me Now into its version 2.0 incarnation is
described first in this installment and is further developed in Part 2 of the series.
Install jQuery and its plug-ins
The first step to adding an Ajax behavior layer to your site is to download all of
your open source libraries. If you downloaded the sample 2.0 application from
the Download section, all the libraries are included. If you
want to download the latest versions of these libraries directly for your own
application, you can once again do so in the Downloads section.
Next, create a /js directory for jQuery and the forms plug-in. Note that
GreyBox, ThickBox, and JTip all need their own directories; they come bundled
with images, CSS files, and multiple JavaScript libraries, all of which assume
a particular directory structure. When linking to your CSS and .js files, you
must also include a short script block to set up the correct root-directory
pointer for GreyBox. This pointer must be an absolute directory path, so you
may need to tweak this value in your own code. When you're done, the head
elements of your HTML files should look like Listing 2.
Listing 2. Customize Me Now 2.0 header element
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Customize Me Now: Shopping Cart</title>
<!--customizemenow assets-->
<link rel="stylesheet" type="text/css" href="../css/customizemenow.css"/>
<!--jquery assets-->
<script type="text/javascript" src="../js/jquery-1.2.1.min.js"></script>
<script type="text/javascript" src="../js/jquery.form.js"></script>
<!--thickbox assets-->
<script type="text/javascript" src="../thickbox/thickbox.js"></script>
<link rel="stylesheet" type="text/css" href="../thickbox/thickbox.css" />
<!--jtip assets-->
<script type="text/javascript" src="../jtip/scripts/jtip.js"></script>
<link rel="stylesheet" type="text/css" href="../jtip/css/jtip.css" />
<!--greybox assets-->
<script type="text/javascript">
/*this needs to be a non-relative reference*/
var GB_ROOT_DIR = "/customizemenow/2/0/greybox/";
</script>
<script type="text/javascript" src="../greybox/AJS.js"></script>
<script type="text/javascript" src="../greybox/AJS_fx.js"></script>
<script type="text/javascript" src="../greybox/gb_scripts.js"></script>
<link rel="stylesheet" type="text/css" href="../greybox/gb_styles.css" />
</head>
|
Convert secondary links into lightboxes using ThickBox
and jQuery forms
Because jQuery and its plug-ins follow a philosophy of progressive enhancement,
you need almost no custom JavaScript code to create your Ajax functionality.
Instead, you add specific attributes to existing HTML tags. Your JavaScript
libraries parse the Document Object Model (DOM) looking for these special
attributes, then add the appropriate behaviors to elements that possess them.
jQuery enables this coding style by parsing the DOM automatically when all the
markup has been rendered. If you peek behind the scenes of your jQuery plug-ins,
you'll see that they all delegate their event models to the core
jQuery object and its ready
method.
Now that you've learned the background, it's time to begin simplifying your navigation with jQuery.
You use ThickBox to transform any page that's not part of the main
purchase path from a regular page into a lightbox page. You begin with the Product
Details page so your users can view it from anywhere on the site without
leaving the "funnel."
ThickBox is easy to invoke. Simply add some special attributes to each relevant
link:
- A
class attribute of thickbox.
This special class attribute signals to
ThickBox that it should pay attention to this element.
- Several querystring values:
-
KeepThis=true and
TB_iframe=true: These values
tell ThickBox to render this link in an iframed lightbox.
-
height=400: The height of
your ThickBox window in pixels. This could be any value, but
for this example, use 400.
-
width=600: The width of your
ThickBox window in pixels. This could be any value, but for
this example, use 600.
Because you're already using the querystring to pass a product code to the
Product Details page, simply append your ThickBox values to the existing URL
using ampersands (&). When you're done adding these attributes to your
Product Details links, each pop-up link should look like
Listing 3.
Listing 3. HTML code for ThickBox links
<a
href="detail.html?product=A&KeepThis=true&TB_iframe=true&height=400&width=600"
class="thickbox">product details</a>
|
Now that you've tackled the Product Details page, retrofit the Comparison page.
The only way to get to this page is through a form submission; users have to
choose which products they want to compare by using check boxes. You can't
render the results of this form submission using ThickBox without leveraging
jQuery Forms, a library that wraps several convenience methods and event hooks
into an object called ajaxForm. Using
ajaxForm and a bit of custom JavaScript code, you
can call ThickBox's tb_show method directly. To
do so, add the script block in Listing 4 to the head of
results.html.
Listing 4. JavaScript code to invoke ThickBox
from a form
<script type="text/javascript">
/*create a thickbox for our form submittal*/
//when the document is ready
$(document).ready(function() {
//wrap form#comparison in an ajaxForm object
$('#comparison').ajaxForm({
//intercept the submit event with a callback
beforeSubmit: function(formData, jqForm, options) {
//serialize form data; append to the form action; tack on ThickBox params
var URL = jqForm[0].action + "?" + $.param(formData);
URL += "&KeepThis=true&TB_iframe=true&height=400&width=600";
//call ThickBox directly
var caption = null;
var imageGroup = false
tb_show(caption,URL,imageGroup);
//cancel the form submission by returning false
return false;
}
});
});
</script>
|
This code block illustrates the simplicity of the jQuery
API. In just a few lines of code, you're intercepting the normal submittal
of an HTML form and executing some custom JavaScript code instead. Using this
technique, you could execute custom validation logic before allowing the form
to be submitted, or you could trigger a custom event after the form is
submitted. In this case, you're going to keep the form from submitting
altogether. Instead, you're going to manually "fake out" the HTTP request that
the form submittal would have generated so that you can redirect the target of
the form to your ThickBox window.
Users are unaware of all this behind-the-scenes action. All they know is that
after submitting the form, they see the results in their modal window.
After looking at your Comparison page, the user can close the ThickBox window
and get back to customizing and purchasing a product.
The only problem with rendering your Product Details and Comparison pages using
ThickBox is that the pages are too wide for your ThickBox window. You could
change the width and height values that you pass in to ThickBox, but what about
users with smaller viewports? You don't want ThickBox to cover the entire
window, let alone extend beyond the edges of the viewport. Instead, simply
re-style details.html and comparison.html by adding a
class of inline to their
body tags. Then, add the CSS declaration from Listing 5
to customizemenow.css.
Listing 5. CSS for ThickBox
#CMN #main.inline {
width: 600px;
}
|
The final step in your modal window implementation is to suppress those elements
of the Product Details and Comparison pages with which you don't want users to
interact. Because these pages are now purely informational, there's no
need to include action links and buttons within them. There's also no need to
show your navbars or other chrome.
You could accomplish this in several ways. You could simply remove these elements
from the pages, but that would defeat your strategy of progressive enhancement.
Users who don't enable JavaScript would end up on these pages with no way to get
off them or advance through the purchase process. You could also append
querystring parameters to your links so that your server-side framework would
render these pages using a different template. In the real world, that's what
you'd probably do. But there's another valid way to handle this, one that
relies on only client-side code: the good old-fashioned
<noscript> tag. If you wrap each element in a
<noscript> tag, it will be seen only by users
of non-JavaScript user agents: the exact users you want to see them.
The resulting HTML code for your headers and footers looks like the code in Listing
6.
Listing 6. HTML code for Customize Me Now 2.0 navigation
<noscript>
<div id="footer" class="nav">
<<ul>
<li><a href="index.html">search&/a></li>
<li><a href="results.html">results</a></li>
<li><a href="detail.html">details</a></li>
<li><a href="comparison.html">compare</a></li>
<li><a href="customize.html">customize</a></li>
<li><a href="cart.html">cart</a></li>
<li><a href="checkout.html">checkout</a></li>
<li class="last"><a href="confirm.html">confirmation</a></li>
</ul>
</div>
</noscript>
|
The HTML for the main content <div> of your
Product Details page looks like the code in Listing 7.
Listing 7. HTML code for details.html 2.0
<div id="main" class="inline">
<form method="GET" action="customize.html">
<input type="hidden" name="product" id="product" value="A" />
<h1>Pizza: Product Details</h1>
<noscript>
<div class="buttons">
<input class="button" type="submit" name="submitTop" id="submitTop"
value="Customize Now" />
or <a href="cart.html?product=A">add to cart with default
options</a>
</div>
</noscript>
<!--[content goes here]-->
<noscript>
<div class="buttons">
<input class="button" type="submit" name="submitBottom" id="submitBottom"
value="Customize Now" />
or <a href="cart.html">add to cart with default options</a>
</div>
</noscript>
</form>
</div>
|
The HTML for the main content <div> of your
Comparison page looks like the code in Listing 8.
Listing 8. HTML code for comparison.html 2.0
<div id="main" class="inline">
<h1>Product Comparison</h1>
<table class="productComparison">
<thead>
<tr>
<th>Product</th>
<th>Pros</th>
<th>Cons</th>
<noscript>
<th>Actions</th>
</noscript>
</tr>
</thead>
<tr>
<td class="name">
<a class="jTip" name="About Pizza" id="pizza" target="productPopup"
href="productPopup.html?product=A">Pizza</a>
</td>
<td class="pros">
<ul>
<li>Great flavor.</li>
<li>Low cost.</li>
<li>Fun with friends.</li>
</ul>
</td>
<td class="cons">
<ul>
<li>Can make you fat.</li>
<li>Not very nutritious.</li>
</ul>
</td>
<noscript>
<td class="action">
<a class="button" href="customize.html?product=A">customize
product</a>
<a class="button" href="cart.html?product=A">add to cart with
default options</a>
</td>
</noscript>
</tr>
<!--[additional table rows here]-->
</table>
</div>
|
 |
The developerWorks Ajax resource center
Check out the Ajax resource center,
your one-stop shop for free tools, code, and information on developing Ajax applications. The active Ajax community forum, hosted by Ajax expert Jack Herrington, connects you with peers who might just have the answers you're looking for right now.
|
|
You can see the results of all this tinkering by viewing the Customize Me Now
2.0 Search Results page in a browser and launching the Product Details or
Comparison pages. It should look like the one in Figure 3.
Figure 3. ThickBox in action
Summary
While this article covered a great deal of material — showing you some Ajax
techniques and best
practices -- we're just getting started. In Part 2 of
this series, you will continue to refine your navigation by transforming pop-up links
into tooltips using JTip. Then, you'll convert off-site links into lightboxes using
GreyBox. Finally, you'll review all the key concepts behind the example application
and examine how they've improved its user experience. If you want to work ahead, you
can dig deeper into the source code for Customize Me Now 2.0 and look at it in
action in a Web browser.
Downloads | Description | Name | Size | Download method |
|---|
| Source code for the original demo app | customizeOnePointZero.zip | 24KB | HTTP |
|---|
| Source code for the retrofitted demo app | customizeTwoPointZero.zip | 88KB | HTTP |
|---|
More downloads Notes - This open-source Ajax toolkit provides the foundation for your Ajax capabilities.
The current version as of this writing is 1.2.1.
- This jQuery plug-in allow you to replace your informational pop-ups with simple,
cross-browser tooltips.
- This plug-in allows you to load your product details and comparison pages inside
a modal window. The example in this article uses version 3.1.
- Because the comparison page requires some form parameters, you must write a bit of
custom JavaScript code to render it with ThickBox. Luckily, this utility library
does most of the work for you.
- This jQuery plug-in lets you link to your manufacturer Web sites in a simple,
gorgeous lightbox. The version in this example is 5.53.
Resources Learn
-
See Customize Me Now 1.0
in action on my Web site.
-
View Customize Me Now 2.0,
with all of the changes, in action on my Web site.
-
Go to the jQuery Web site to learn all about jQuery and
find additional plug-ins.
- Visit the Learning jQuery Web site to participate in the
jQuery community and access tutorials and forums.
-
The developerWorks Web development zone is packed with tools and information for Web 2.0 development.
-
The developerWorks Ajax resource center contains a growing library of Ajax content as well as useful resources to get you started developing Ajax applications today.
- Read
"Simplify
Ajax development with jQuery" (Jesse Skinner, developerWorks, 10 Apr 2007) to learn about the jQuery philosophy, discover its features and functions, perform some common Ajax tasks, and find out how to extend jQuery with plug-ins.
- "Ajax and XML:
Ajax for lightboxes" (Jack Herrington, developerWorks, 25 Sep 2007) teaches you how
to implement lightboxes and tooltips with the Prototype JavaScript library.
-
Read
Learning
jQuery
to get started with jQuery.
-
Check out the book
jQuery
in Action
for additional jQuery help.
- Turn to the
jQuery
Reference Guide
for a more general jQuery resource.
-
Check out Brian Dillard's blog, Agile Ajax,
for more on jQuery and other UI topics.
-
Stay current with developerWorks
technical events and Webcasts.
-
Browse the technology
bookstore for books on these and other technical topics.
Discuss
About the author  | 
|  | In his 12 years as a Web developer, Brian J. Dillard has built rich user interfaces for companies as diverse as Orbitz Worldwide, Reflect True Custom Beauty, Archipelago
LLC, and United Airlines. Now serving as RIA Evangelist at Pathfinder Development in
Chicago, Illinois, Brian builds rich Internet applications for a variety of clients,
participates in open source projects, and contributes to the Agile Ajax blog. He is
the project lead on Really Simple History, an Ajax history and bookmarking library
used in the production code of thousands of Web sites. |
Rate this page
|  |