Ajax in Action. Chapter 6: The User Experience | 2
Ajax in Action. Chapter 6: The User Experience
Finally, we need to stress the importance of simplicity. Ajax allows you to do a number of wild and creative things, the likes of which have never been seen in a web page before. Some of these things have never been seen because the necessary technology is only just arriving on the scene. In other cases, there are good reasons for not implementing a feature. Spring-loaded menus that bounce onto the screen and gradually dampen their oscillations may be great fun to code and great fun for a short-term user dropping by for five minutes to let off steam. If the user is going to use the application for several hours a day, though, she is less likely to appreciate the fun by the day's end.
It is always worth asking whether a new feature will actually improve the end experience. In many cases with Ajax, the answer will be yes, and the developer can concentrate on coding features that will be genuinely beneficial.
6.1.5 Making it work
It's probably the case that your code doesn't exhibit all the features we just mentioned. Mine certainly doesn't. These are merely ideals that we've presented. Making the effort to move toward these ideals can pay big dividends when it comes to maintaining your codebase in the future, and refactoring existing code can introduce these qualities as you go along. Choosing where to concentrate the effort is something of a black art, and the only way to get good at it is by practicing. If you're new to refactoring, start with something small and gradually work outward. Remember, refactoring is an incremental process, and you can add quality to your code without pulling it apart and leaving bits on the floor for weeks on end.
In the remainder of this chapter, we'll look at some specific features that you can build into Ajax applications. A large part of the chapter focuses on notification frameworks, which are ways of keeping the user informed while background processes such as calculations or network requests take place. By providing the user with a visual cue that the process is under way, we improve the responsiveness of the application. By running all such notifications through a common framework, we ensure that presentation is consistent and make it simple for the user to work with the notifications because everything works in the same way.
Let's start off by looking at the various ways in which we can notify the user of events taking place within the application.
6.2 Keeping the user informed
In an Ajax application, we may often need to run off across the network and fetch some resources from the server and then pick up the results in a callback function and do something with them. If we were handling server requests synchronously, we would have a relatively easy time working out how to handle this in user interface terms. The request would be initiated, the entire user interface would lock up and stop responding, and when the results come back from the server, the interface would update itself and then start responding to input. What's good for the developer here is lousy for the user, of course, so we make use of an asynchronous request mechanism. This makes the business of communicating server updates through the user interface that much more complicated.
6.2.1 Handling responses to our own requests
Let's pick up a concrete example to work with. The planetary information viewer that we developed in chapter 5 allowed the user to update a couple of editable properties for planets: the diameter and the distance from the sun (see section 5.5). These updates are submitted to the server, which then responds, saying whether it has accepted or rejected them. With the introduction of the command queue concept in section 5.5.3, we allowed each server response to carry acknowledgments to several updates from a given user. A sample XML response document follows, showing one successful and one unsuccessful command:
Let's recap where we had left this code before we start refactoring. Here is
our implementation of the Command object's
as presented in chapter 5:
This is good proof-of-concept code, ripe for refactoring into something more polished. As it stands, if the update is successful, nothing happens at all. The local domain model was already updated before the data was sent to the server, so everything is assumed to be in sync with the server's domain model. If the update fails, then we generate an alert message. The alert message is simple for the developer but makes for poor usability, as we will see.
Let's return to our user, who is probably no longer thinking about the albedo of the planet Mercury. She is suddenly confronted with a message in an alert box saying, "Failed to update albedo to 180 value out of range," or something similar. Taken out of context, this doesn't mean very much. We could upgrade our error message to say "Failed to update albedo of Mercury...," but we would still be interrupting the user's workflow, which was the reason that we switched to asynchronous message processing in the first place.
We would, in this particular case, also be creating a more serious problem.
Our editable fields implementation uses the
onblur event to initiate
the process of submitting data to the server. The
is triggered whenever the text input field loses focus, including when it is
taken away by an alert box. Hence, if our user has moved on to editing another
property and is midway through typing into the second textbox, our alert will
result in the submission of partial data and either mess up the domain model
on the server or generate an errorand a further alert box if our validation
code catches it!
A more elegant solution than the alert box is needed. We'll develop one shortly, but first let's further complicate the picture by considering what other users are up to while we make our requests to the server.
Created: March 27, 2003
Revised: October 31, 2005