Chapter 2. Designing Ajax Applications: Thinking Ajaxian

image with no caption

Welcome to Ajax apps—it’s a whole new web world.

So you’ve built your first Ajax app, and you’re already thinking about how to change all your web apps to make requests asynchronously. But that’s not all there is to Ajax programming. You’ve got to think about your applications differently. Just because you’re making asynchronous requests, doesn’t mean your application is user-friendly. It’s up to you to help your users avoid making mistakes, and that means rethinking your entire application’s design.

Mike’s traditional web site

Note

Note from HR: Can we use a less offensive term? How about “consistently annoys every one of Mike’s users”?

Mike’s got the hippest movie reviews going, and he’s taking his popular opinions online. Unfortunately, he’s having problems with his registration page. Users visit his site, select a username, type in a few other details, and submit their information to get access to the review site.

The problem is that if the username’s taken, the server responds with the initial page again, an error message... and none of the information the user already entered. Worse, users are annoyed that after waiting for a new page, they get nothing back but an error message. They want movie reviews!

Note

Users shouldn’t have to fill out eight fields to find out if the data in the first field is valid.

image with no caption

Let’s use Ajax to send registration requests ASYNCHRONOUSLY

Ajax is exactly the tool you need to solve the problem with Mike’s page. Right now the biggest problem is that users have to wait for a full page refresh to find out their requested username is already taken. Even worse, if they need to select a different username, they’ve got to re-type all their other information again. We can fix both of those problems using Ajax.

Note

Did you write down something similar to this as Mike’s biggest problem?

We’ll still need to talk to the server to find out whether a username has been taken, but why wait until users finish filling out the entire form? As soon as they enter a username, we can send an asynchronous request to the server, check the username, and report any problems directly on the page—all without any page reloads, and without losing the user’s other details.

Note

It’s okay if you didn’t think about sending the request as soon as the user types in their username... but bonus credit if you did!

image with no caption
image with no caption

Don’t annoy your users... ever!

On the Internet, your competitors are only a click away. If you don’t tell your users about a problem right away, or if you ever make them re-do something, you’re probably going to lose them forever.

Mike’s site may not be a big moneymaker (yet), or even seem that important to you... but it might to his fans. One day a user you’re helping him not annoy may land him a six-figure income writing movie reviews for the New York Times. But Mike won’t ever know if his site is hacking his users off. That’s where your Ajax skills can help.

Update the registration page

The basic structure of Mike’s registration page is already in place, so let’s go ahead and add a <script> tag to load the JavaScript we’ll write. Then, we can set up the username field on the web form to call a JavaScript function to make a request to the server.

Watch it!

Use an opening and closing <script> tag.

Some browsers will error out if you use a self-closing <script> tag, like <script />. Always use separate opening and closing tags for <script>.

image with no caption

Run it!

Download the registration page’s XHTML and CSS.

If you haven’t already done so, download the sample files for the chapter from www.headfirstlabs.com. Look in the Chapter2 folder for the file named registration.html, and then add the script tag shown in bold.

image with no caption

Separate your page’s content from its behavior.

We could call the JavaScript directly from the XHTML by, for example, putting an onblur event in the username form field. But that’s mixing the content of our page with its behavior.

The XHTML describes the content and structure of the page: what data is on the page, like the user’s name and a description of the movie review site, and how it’s organized. But how a page reacts to the user doing something is that page’s behavior. That’s usually where your JavaScript comes in. And the CSS defines the presentation of your page: how it looks.

Keeping content, behavior, and presentation separate is a good idea, even when you’re building a relatively simple page all by yourself. And when you’re working on complex applications that involve a lot of people, it’s one of the best ways to avoid accidentally messing up somebody else’s work.

Brain Barbell

How do you think separating the content of a site from its presentation and behavior makes it easier to change?

Set the window.onload event handler... PROGRAMMATICALLY

We want some JavaScript code to run when the registration page loads, and that means attaching that code as the event handler on one of the first page events, window.onload.

And we can do that programmatically by setting the onload property of the window object. But how do we do that? Let’s look at exactly what happens when the registration page is requested by a user visiting Mike’s movie review site:

First, a user points their browser at Mike’s registration page.

image with no caption

Then, the browser starts parsing the page, asking for other files as they’re referenced.

image with no caption

If the file is a script, the browser parses the script, creates objects, and executes any statements not in a function.

image with no caption

Finally, after all referenced files are loaded and parsed, the browser triggers the window.onload event and calls any function that’s registered to handle that event.

Note

All of this happens before you can actually use the page... so it’s lightning fast!

image with no caption

Code in your JavaScript outside of functions runs when the script is read

image with no caption

We want to set an event handler up to run as soon as a user loads the registration page. So we need to assign a function to the onload property of the window object.

And to make sure this event handler is assigned as soon as the page loads, we just put the assignment code outside of any functions in validation.js. That way, before users can do anything on the page, the assignment happens.

image with no caption

Run it!

Create the initial version of validation.js.

Create a new file called validation.js in a text editor, and add the function declarations shown above. Remember to assign the initPage() function to the window object’s onload property!

What happens when...

There’s a lot going on in this step. Let’s go through it to make sure everything’s happening exactly when we want it to.

First...

When the browser loads the XHTML file, the <script> tag tells it to load a JavaScript file. Any code that’s outside of a function in that script file will be executed immediately, and the browser’s JavaScript interpreter will create the functions, although the code inside those functions won’t run yet.

image with no caption

...and then...

The window.onload statement isn’t in a function, so it will be executed as soon as the browser loads the validation.js script file.

The window.onload statement assigns the initPage() function as an event handler. That function will be called as soon as all the files the XHTML refers to have been loaded but before users can use the web page.

Note

Even though these happen in sequence, ALL of this occurs before users can interact with the web page.

image with no caption

...and finally...

The initPage() function runs. It finds the field with an id of “username.” Then, it assigns the checkUsername() function to the onblur event of that field.

This is the same as putting onblur="checkUsername()" in the XHTML. But our way is cleaner because it separates the code (the JavaScript function) from the structure and content (the XHTML).

image with no caption

And on the server...

Before we can test out all our work on Mike’s registration page, we need to check out the server. What does the server need to get from our request? What can we expect from the server?

image with no caption

Some parts of your Ajax designs will be the same... every time

We’ve already used window.onload and an initPage() function twice: once for Rob’s rock and roll store, and again for Mike’s registration page. Next up is creating a request object that works the same for the registration page as it did for Rob’s rock and roll site.

In fact, lots of things in Ajax apps are the same. Part of your job, though, is to build code so you don’t have to write those same bits of code over and over again. Let’s see how creating and using a request object looks in Mike’s movie review site:

Note

Good application designers look for similarities and find ways to reuse code from other designs and applications.

image with no caption

createRequest() is always the same

Watch it!

IE 5 on the Mac still doesn’t work, even with this browser-independent code.

We need a function to create a request object in almost every Ajax application... and we’ve already got one. It’s the createRequest() function you saw back in Chapter 1, in fact. Let’s take a closer look at how this function creates a request in all types of situations, with all types of client browsers.

image with no caption
image with no caption

Copy and paste is not good code reuse.

The createRequest() function for Mike’s movie site is identical to the createRequest() function from Rob’s site in Chapter 1. And copying that code from the script you wrote in Chapter 1 into your new validation.js is a bad idea. If you need to make a change, you’ll now have to make it in two places. And what do you think will happen when you’ve got ten or twenty Ajax apps floating around?

When you find code that’s common across your apps, take that code out of application-specific scripts, and put it into a reusable utility script. So for createRequest(), we can pull it out of validation.js in the movie site and create a new script. Let’s call it utils.js and start putting anything that’s common to our apps into it.

Then, each new app we write can reference utils.js, as well as a script for application-specific JavaScript.

image with no caption
image with no caption

Separate what’s the same across applications, and turn that code into a reusable set of functions.

Create a request object... on multiple browsers

It’s time to break into JavaScript and figure out exactly what’s going on. Let’s walk through exactly what each piece of createRequest() does, step by step.

image with no caption
  1. Create the function

    Start by building a function that any other code can call when it needs a request object.

    image with no caption
  2. Try to create an XMLHttpRequest for non-Microsoft browsers

    Define a variable called request, and try to assign to it a new instance of the XMLHttpRequest object type. This will work on almost all browsers except Microsoft Internet Explorer.

    image with no caption
  3. Try to create an ActiveXObject for Microsoft browsers

    In the catch block, we try to create a request object using the syntax that’s specific to Microsoft browsers. But there are two different versions of the Microsoft object libraries, so we’ll have to try both of them.

  4. If all else fails, return null

    We’ve tried three different ways of obtaining a request object. If the parser reaches this request block, that means they’ve all failed. So declare request as null, and then let the calling code decide what to do about it. Remember, null is the object you have when you don’t have an object.

  5. Put it together, and return request

    All that’s left is to return request. If things went okay, request points to a request object. Otherwise, it points to null:

    image with no caption

Ajax app design involves both the web page AND the server-side program

Even though there was already a web form for Mike’s registration page, we’ve got to interact with that form to get the user’s username, and later on, to update the page with an error message if the selected username’s taken.

And even though we’re letting someone else worry about writing the server-side code, we’ve still got to know what to send to that code... and how to send that information.

Take a look at the steps we need to perform to check a username for validity. Most of these steps are about interacting with either the web form or a server-side program:

  1. Try to get a request object

    Note

    This is what the call to createRequest() does.

  2. Show an alert if the browser can’t create the request

    Note

    Remember, createRequest() doesn’t handle errors, so we’ll need to do that ourselves.

  3. Get the username the user typed into the form

    Note

    This interacts with the web form.

  4. Make sure the username doesn’t contain problematic characters for an HTTP request

    Note

    These have to do with getting the username to the server.

  5. Append the username to server url

  6. Tell the browser what function to call when the server responds to the request

    Note

    This is the “callback.” We’ll write it in a few pages.

  7. Tell the browser how to send the request to the server

  8. Send the request object

    Note

    Now we’re through until the request returns, and the browser gives it to the callback.

    Here’s more server interaction.

Good Ajax design is mostly about interactions. You’ve got to interact with your users via a web page, and your business logic via server-side programs.

What we’ve done so far...

Now we’ve got everything ready to make a request to the server when a new username is entered in.

image with no caption

What we still need to do...

Now we’re just about ready to actually have the server respond to our request:

image with no caption
image with no caption

Asynchronous apps behave differently than traditional web apps, and your debugging has to account for that.

Asynchronous applications don’t make you wait for a server’s reply, and you don’t get an entire page back from the server. In fact, most of the interactions between a web page and a server in asynchronous apps are completely invisible to a user. If the user’s web browser runs into a problem when it executes some JavaScript, most of the time it will just stop, and you’ll have no idea what happened.

Alerts are a good way to track down problems the browser doesn’t tell you about. Alerts show you what the browser sees. They let you know what’s going on in the background while your users are happily typing away.

Note

You’ll want to take out all these alerts once you’ve tracked down any problems.

You can’t usually rely on a server to tell you there’s a problem in asynchronous apps. It’s YOUR job to figure out if there’s a problem, and respond to it in a useful manner.

The request object connects your code to the web browser

All we have left to do is write the code that the browser will call when the server responds to the request. That’s where the request object comes into play. It lets us tell the browser what to do, and we can use it to ask the browser to make a request to the server and give us the result.

But how does that actually happen? Remember, the request object is just an ordinary JavaScript object. So it can have properties, and those properties can have values. There are several that are pretty useful. Which do you think we’ll need in our callback function?

image with no caption

The browser makes the server’s response available to your code through the properties of the request object.

You talk to the browser, not the server

Although it’s easy to talk about your code “sending a request object to the server,” that’s not exactly what happens. In fact, you talk to the web browser, not the server, and the browser talks to the server. The browser sends your request object to the server, and the browser translates the server’s response before giving that response data back to your web page.

image with no caption

The browser calls back your function with the server’s response

image with no caption

Show the Ajax registration page to Mike...

Everything works. But when you give all your code to Mike, and he goes live with the new improved registration page, there are still some problems:

image with no caption

What happened? Did all the work you put into the registration page get lost? Ignored?

What do YOU think?

The web form has TWO ways to send requests to the server now

Suppose a user does just what you expect: they enter a username, and while an asynchronous request is going to the server and getting handled by the browser, your callback is running, and the user’s filling out other information on the form. Everything works great—just like you planned.

But suppose the user’s so eager to get to Mike’s review of Iron Man that they put in their username, ignore everything else on the form, and click “Register.” What happens then?

image with no caption
image with no caption

Frank: Well, we can’t keep users from skipping over fields, but maybe we can keep them from getting ahead of our request.

Jill: You mean validating the username? Yeah, that’s perfect, but how do we do that?

Frank: How about we just disable the Register button until the server responds to the username validation request.

Jill: That would solve this problem, but it seems like we need something more.

Frank: Like what? They’re submitting the form too soon, so if we prevent the submission, the problem’s solved.

Jill: Well, don’t you think we need to give the user some idea about what’s going on?

Frank: They’ll know what’s going on when we enable the button. Until then, they should be filling out the form, not trying to click ‘Register.’

Jill: But don’t you think that might be confusing? If the user finishes filling out the form, or doesn’t want to fill it all out, then they’re just going to be sitting there, stuck, and they won’t know why.

Frank: Well, we need to let them know the application is doing something. What about displaying a message?

Jill: Another alert? That’s just going to annoy them in a different way. How about a graphic? We could display an image when we send the request to the browser...

Frank: ...and another when their username’s verified.

Jill: Hey, and if we used an image to show whether the username is okay or not, we could get rid of the alert when there’s a problem with the username, too.

Frank: Perfect! Visual feedback without annoying popups. I love it!

You can never assume your users will do things exactly the way you do... plan for EVERYTHING!

image with no caption
image with no caption

Brain Power

What do you think about this approach? Does it follow the principle of separating content from presentation? Would you change anything?

image with no caption

Try and keep your presentation in your CSS, and your behavior in your JavaScript.

Your XHTML stores structure and content. Your CSS should handle presentation, like images, colors, and font styles. And your JavaScript should be about what your page does: the page’s behavior. Mixing those means that a designer won’t be able to change an image because it’s in your code. Or a programmer will have to mess with a page author’s structure. That’s never a good thing.

It’s not always possible, but when you can, keep your presentation in your CSS, and use JavaScript to interact with the CSS rather than affecting the presentation of a page directly.

Let’s create CSS classes for each state of the processing...

Instead of changing an image directly, let’s put all the image details in our CSS. Open up movies.css and add the following CSS selectors:

image with no caption

... and change the CSS class with our JavaScript

Now our JavaScript doesn’t need to know any image names, paths, or anything about how the process icons are being shown. Instead, we just need to know the three CSS classes that represent each stage of processing.

image with no caption

Now we can update our JavaScript (again). This time we’ll just change the CSS class instead of directly changing an image:

image with no caption
image with no caption

Changes? We don’t need no stinkin’ changes!

Mike’s web designer made lots of changes... but she didn’t change the names of the CSS classes for each stage of processing. That means that all your JavaScript still works, with no updates! When you separate your content from your presentation, and separate both from your behavior, your web application gets a lot easier to change.

In fact, the CSS can change anytime, and we don’t even need to know about it. As long as those CSS class names stay the same, our code will happily keep on working.

Good separation of content, presentation, and behavior makes your application a lot more flexible.

Only allow registration when it’s appropriate

With process indicators in place, all that’s left is to disable the Register button when the page loads, and then enable the button once a username’s okay.

That involves just a few more changes to validation.js:

Disable the Register button

 

When a user first loads the page, the username hasn’t been checked. So we can disable the Register button right away in our initialization code.

image with no caption

Enable the Register button

 

If the username is okay, the user’s ready to register, so we need to enable the Register button. But if there’s a problem with the username, they need to try again, so we should keep the Register button disabled. And just to make things easier for the user, let’s move them back to the username field if their username is rejected:

image with no caption

Watch it!

The image files referenced in your CSS are in the download folder from Head First Labs.

Be sure you’ve got the complete examples folder from Head First Labs, including the process indicator image.

image with no caption

Now Mike’s page...

  • ...lets users keep working while their requested usernames are verified by Mike’s server.

  • ...prevents user mistakes by disabling buttons that aren’t safe or appropriate to use, and enables those buttons when they are useful.

    Note

    Along the way you started thinking about application design in an entirely new way... going beyond a traditional request/wait/response model.

  • ...doesn’t annoy his users with intrusive popups, but still gives them useful visual feedback.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.193.81