Chapter 7

CREATING INTERACTIVITY WITH JAVASCRIPT


JavaScript is one of the three basic building blocks of the Web. If you think about web technologies as a pyramid, HTML/XHTML is one corner of that pyramid handling the actual content of a page. CSS is another corner, adding style to your pages and allowing you to lay them out in a way that is not only attractive but also adds visual impact. JavaScript is the third corner, allowing pages to do more than just be static documents.

One of the biggest questions amongst those who are new to the Web is, what's the difference between JavaScript and something like PHP? The big difference is that JavaScript is executed on the client side (in the visitors' browsers), whereas PHP runs on the server. So in other words, JavaScript actually makes use of the processor(s) on your end users' computers.

The advantage you get is that things seem to happen instantly in the browser. Using JavaScript, you can make your pages feel more like an application running on the clients' computers. JavaScript operations don't require a round-trip to the server and back; pages aren't submitted, processed, and then returned.

This speed comes with a price, though. Because you're not processing on the server, you don't have access to certain features. You can't, for example, save something to or get something out of a database management system on a remote host using JavaScript. It would be impossible to write a real-time chat application using JavaScript alone, for example. You can't manipulate files or send and receive e-mail. And individuals have the option to turn JavaScript off in their web browser, meaning you can't do anything with JavaScript at all (so you'd best have a backup plan). You can do some pretty cool things, though, for those people who will let you.

JavaScript basics: origin and background

You can probably guess, based on everything you've read about the history of web standards, that JavaScript hasn't had a smooth journey to where it is today. JavaScript began life as a Netscape development and was initially supported in Netscape Navigator 2 (around the end of 1995). Microsoft quickly fired back with its own implementation, which it called JScript (first supported in Internet Explorer 3 in 1996). Although the two languages were similar, some differences did exist, such as in the way each implementation enabled programmers to find the current date and time.

The dark ages of scripting

JavaScript and JScript really fell from grace with developers for some time because of the differences between browsers. It was one thing to have to write "hacks" in order to get a certain CSS declaration to work properly across browsers; it was something entirely different to have to write multiple versions of your scripts in order to get them to behave consistently. The DOM really was a breakthrough on this front and ushered in the ability for developers to, once again, write a single script that would work everywhere.

Netscape submitted the JavaScript language to the European Computer Manufacturers Association (ECMA), an international standards organization, for standardization in 1996, and it was accepted shortly thereafter. This became the basis of ECMAScript, which is, essentially, a compromise between Microsoft and Netscape on a core set of functions for a scripting language. ECMAScript is the core, and then JavaScript and JScript both extend the functionality.

With the introduction of the DOM recommendation and support from the browser manufacturers, we started to see an upsurge in really innovative web applications being introduced; in fact, it wouldn't be too much of a stretch to credit the entire Web 2.0 technological leap to the introduction of DOM support.

Object-based programming

An object is a collection of properties. Those properties may be really simple pieces of data, they may be other objects, or they may be functions (methods). JavaScript has a number of built-in objects, such as an Image object and a Date object, but developers are free to define their own objects as well.

Objects are really useful because they can have global properties that exist in all instances of an object, as well as assign individual properties (or change properties) for certain instances. This is a feature of object-oriented languages called modularity; variables and functions can be defined once and then reused in multiple places. Besides the obvious benefit to developers in that they need to write something only once, it also eases maintenance: as new functionality is needed in a particular area, the reusable function being called can be updated, and changes will propagate throughout.

It's probably easiest to illustrate this concept with an example. Say you have a number of download registration forms scattered throughout your website. These forms ask for a variety of information, but one thing they all have in common is that you have to enter an e-mail address. You write a function that can be called when a form is submitted that checks the e-mail field to make sure that it's not left blank. Problem solved.

Three weeks later, you're doing maintenance on your registration database, and you notice a bunch of e-mail addresses that look like asdf and sdfhsdg. It seems that instead of entering an actual e-mail address, people are just punching in some random characters in order to bypass the form and download the file they want. It's easy for you to make a few tweaks to your e-mail address checker function and have it instantly update everywhere on the website, because you've reused that function object throughout.

Another feature of object-oriented programming used by JavaScript is that of encapsulation. Encapsulation hides all the steps of a particular function and allows you to simply call that function by its name. This greatly improves the readability of code by simplifying and shortening it.

An example of encapsulation would be with an Ajax function that updates a <div> on a page with the results of a database query when you click a button. So, although you might just have this:

<input type="button" onclick="updateDiv('results')," />

the actual steps involved in updateDiv() may be to take some value from somewhere, submit it to a program on the server, retrieve data from a database, format that output a particular way, and then display it within the <div> you've specified. Imagine what your code would look like if every time you wanted to have this happen you had to explicitly type this series of commands.

What is the Document Object Model?

The Document Object Model (DOM) is a standard way in which web browsers represent HTML and XML documents. It defines a hierarchy amongst elements on a page so that individual page elements can be addressed by your JavaScript code. In other words, the DOM lets you tell your scripts what part of the page to act on. Figure 7-1 shows a representation of a part of the DOM involving a form field.

image

Figure 7-1. Elements within a page are encompassed in a hierarchy known as the Document Object Model.

Standardizing on the DOM API really brought the different JavaScript implementations into greater compatibility with one another. The DOM brought about a standard way for things such as JavaScript to interact with elements encoded in HTML.

getElementById()

One of the really great things that came about with DOM support in browsers is the getElementById() function. Using this function, you can retrieve and change the values of a number of different properties of the various elements on your page. IDs assigned to elements on a web page must be unique (you can't have two <div id="navigation"> elements on your page). As such, you can address elements by their unique ID easily. Here are a few examples of some of the things you can do with a text box:

<input type="text" name="FirstName" id="FName" />
<div id="result"></div>

You can retrieve the value of that text box and assign it to a variable:

var FirstName = document.getElementById('FName').value;

You can change the appearance of that text box (for example, to highlight it if the input fails validation):

document.getElementById('FName').style.border = "2px solid red";

You can easily return the value that was entered in an alert:

alert("You just entered " + document.getElementById('FName').value);

Or you can take the value from one text box and output it in a <div> (or some other element) on the page:

document.getElementById('result').innerHTML = image
"My bologna has a first name, it's " + image
document.getElementById('FName').value;

The point here is that it's really easy to target any element on a page that has an ID.

JavaScript: the basics

As with a number of things on the Web, there's more than one way to do it (which is one of the mottos of Perl, another programming language). You can mix your JavaScript code right in with your HTML markup, or you can separate it completely and store your scripts in separate files. In the following sections, you'll look at three different ways to implement JavaScript within your pages: linking, embedding, or putting code inline. Whenever possible, it's best to try to keep your JavaScript separated from your markup—but sometimes, it may be appropriate to use inline code if you're developing an idea and need to quickly mock something up.

Linking code (separating form from function)

JavaScript files are typically given a .js file extension. They are just plain-text files containing any bits of JavaScript code you'd like. These files can then be linked to in either the <head> or <body> of your pages:

<script type="text/javascript" src="script.js" />

This is definitely the best-practice approach because it creates a clear separation between the content contained in your markup and any interactivity or behaviors that you're including in your pages. Taking this approach, you can then call any functions defined in the script.js file on any number of pages (that contain a link to script.js) and reuse those functions throughout your entire website.

Embedding JavaScript

Your second option is to embed the actual JavaScript code in your page. This is a less desirable option for a couple of reasons: there is less separation between form and function. You are also throwing away one of the great benefits to JavaScript's object-oriented nature: code reuse.

Let's say you write a function to check to make sure a text box on a form isn't left empty (a common practice when you're validating a form's input). If you embed that function in a page, that function can be called only from within that page. You would have to rewrite it (or at the very least copy and paste it) into any other pages that required similar functionality. This concept might seem familiar to you: it's similar to the way CSS works. If you put your style declarations in a page, as opposed to just linking/importing them from an external file, you'll find yourself doing a lot more typing.

Nevertheless, sometimes when you're working out the bugs of a tricky piece of code, it's handy to have it embedded right in your page so that you do not have to flip between multiple text editors. Here's how you would embed JavaScript into an HTML page:

<script type="text/javascript">
    function checkTextBox () {
        /* Some code */
    }
</script>

Embedding JavaScript in the <head> and embedding JavaScript in the <body> are no different from one another. It's simply a matter of choice: some developers like to keep related code together, whereas others think that all scripts should be grouped together in the <head> so that you know exactly where to look instead of hunting through markup. If you're going to embed your JavaScript, try to pick one convention and stick to it.

Inline JavaScript

Again, one step down the ladder of properly separating form from function is putting JavaScript inline. This is definitely the worst way to do it, because your code is completely isolated to a particular place and cannot be reused in other places. That said, if you're just trying to work out a functional mock-up of something and you don't want to bother with defining functions and such, a little inline scripting might just do what you need (just be sure to clean it up before you launch the site!).

Here's an example that changes the display property of a <div> by clicking a link:

<a href="#" onclick="document.getElementById('mydiv') image
.style.display='block'; return false;">Click me!</a>
<div id="mydiv" style="display: none;">
    This is sneaky hidden content until the link is clicked.
</div>

Commenting your code

There are a couple of ways to put comments in your JavaScript code. You can insert large blocks of comments or put in single-line comments. How much commenting you do is up to you; it's a good rule of thumb to comment your code when needed so that someone of a skill level equal to your own would be able to figure out what you're doing. If you've just written something and you think to yourself that it's not completely obvious how it works, then drop in a short comment.

Don't go overboard on commenting your code. Any comments included in code have to be downloaded by end users, so if you double the length of your page by heavily commenting your code, you're also doubling the size of the file that has to be transferred. If you have a lot to say, include a comment pointing them to a readme file or some other piece of documentation that will bring users up to speed.

Another option is to use a JavaScript "compressor" script that will strip away comments and unnecessary whitespace. The code that these scripts produce is streamlined but difficult to read, so it's a good idea to run them on a copy of your .js files and to keep a "readable" copy to which you can make your edits. Packer (http://dean.edwards.name/packer/) is a really good one; CodeTrimmer (http://www.twinhelix.com/javascript/codetrim/demo/) is another pretty good one.

Multiline comments in JavaScript are identical to multiline comments in CSS. A block of comments can be enclosed by a slash-asterisk pair and an asterisk-slash pair to terminate the block. In JavaScript, a single-line comment is indicated by two forward slashes.

/* Multiline comments may be surrounded
by a slash-asterisk and asterisk-slash. */

var foo = 1; // Single-line comments are preceded by two slashes.

One of the handy things about the "two slash" method of commenting is that those comments can stand alone on a line by themselves, or they can be appended to the end of a line of code. So, you can use them to explain what a particular calculation is doing or what a specific variable is for.

Basic programming features

The following are some basic programming features.

Primitive data types

JavaScript has five primitive data types that are the basics from which more complex data types can be derived. String, number, and Boolean are real data types, which are capable of storing data. The other two data types, null and undefined, come about at specific times.

String data type

The string data type is used to store text (zero or more characters) surrounded by single or double quotation marks. Unlike other programming languages, in JavaScript there is no difference between a single character and a number of characters (they're both just strings). Strings are associated with a string object and can be manipulated using a number of built-in JavaScript methods (for example, .length() returns the number of characters in a string).

There are a number of special characters (see Table 7-1) that are represented by special character codes. Because strings are enclosed by quotation marks, for example, you can't just type a quotation mark in your string:

var s = "This string would throw a "syntax error" image
because the quotes are not escaped";

Table 7-1. Common Escape Codes in JavaScript

Escape Code Character Represented
Tab
TabNew line (line feed)
Carriage return
" Double quote
' Single quote
\ Backslash

You can also represent special characters using octal, hexadecimal, or Unicode character codes. For example, the letter e with an acute accent, é (as is commonly used in French), can be represented by u00E9. A good reference for other Unicode character codes is available at http://unicode.org/charts/.

Number data type

The number data type includes both integer and floating-point values (whole numbers and decimals). JavaScript even supports scientific notation, represented with a lowercase e. These are all valid numbers in JavaScript:

17
42.3
47e5
-15.2
.4321e-56

As with strings, numbers are associated with a number object, allowing you to use a range of built-in methods for numeric manipulation (toPrecision(), for example, outputs a number rounded to a specified number of decimal places).

You will likely run into the NaN value when working with numbers in JavaScript. If you ever get NaN back from a script you've written, it literally means "not a number." This occurs when you have an undefined operation. You'll commonly see this if your script thinks that one of your numbers is actually a string and then you try to perform math using that value.

Boolean data type

A Boolean is a true or false value. Booleans are commonly used in if/else statements and in while loops. They are also commonly used to define an object's properties. For example, JavaScript has a built-in function that will check whether a variable is not a number (isNaN()). The result of this function will be either true or false.

Undefined and null

The undefined data type is used when a value has not been set. For example, in JavaScript it's completely acceptable to declare a variable without assigning it a value:

var noVal;

noVal is given the undefined type and value by default. A null data type must be purposefully set but indicates an empty value (nothing):

var nullVal = null;

However, if you compare the value of a variable with an undefined type and a null type, they will compare equal:

var noVal;
var nullVal = null;
if (noVal == null) {
    // this is true
}
if (noVal == nullVal) {
    //this is also true
}

Functions

A function is a collection of bits of JavaScript code, all packaged together, that can be executed all in one go. Although it's possible to write JavaScript that isn't contained within a function (such as inline), it's a lot easier to reuse your code if all you have to do is call a function by name. Functions allow you to implement a lot of those really useful features we talked about in the earlier "Object-based programming" section.

Before you can call a function, it must be defined (in other words, you have to say what that function does). It doesn't need to be defined physically before it's called (above it on the page), but it does need to be "spelled out":

<script type="text/javascript">
    function doSomethingCool(myinput) {
        /* All of the cool stuff this
function does */
    }
</script>

Functions can be declared with no parameters, with one parameter (myinput in the previous example), or with multiple parameters separated by commas.

Passing parameters

What good would a function be if it were isolated from the rest of the page? You need to be able to hand information into it so that it can be processed. You can do this in a couple of ways; we covered one way in the earlier discussion of getElementById(), and the other way is that you can pass a parameter (or multiple parameters) to a function.

The advantage of this approach is that on a page that is dynamically generated, you may not know the ID of each and every element. For example, in a shopping cart, you could have any number of items listed. Let's say you have a couple of buttons beside each item that let you increase and decrease the quantity with a click.

From a code cleanliness standpoint, it's better to simply output a line for each item in the cart and pass the item ID to a JavaScript function than it is to dynamically generate separate JavaScript functions for each item, where each function would essentially do the same thing:

<input type="button" value="+" onclick="inQuan('item593')," image
id="item593" />

If more parameters are passed than expected, the extra parameters are simply ignored. If you pass fewer parameters, those "missing" parameters are given an undefined value. If you're still not satisfied and you want to be able to throw even more data at your function, you can pass arrays as parameters. Arrays are special types of variables that hold multiple values.

If you were already familiar with other programming languages, such as C++, you would expect the parameter passed to be a reference to the original value. Unfortunately, you would be wrong. If you're scratching your head over that previous sentence, we'll use an example to illustrate:

<script type="text/javascript">
     var x = 4;
     squareIt (x);
     alert(x);
     function squareIt(value){
      value = value * value;
      }
</script>

Quick quiz: what will be displayed in your alert? If you answered 16, you're wrong. The correct answer is 4. The function received the value of x but did not alter x in any way.

The exception to this is if you pass an object as a parameter. Passing an object actually passes a reference to that object so that any property of that object is available within the function.

Receiving output from

The best relationships are give and take, however. JavaScript would be pretty limited in its usefulness if it was just a big black hole into which data could be passed but no output could be obtained. Let's look at returning values now and how you can get output from JavaScript.

function inQuan(itemid) {
    var quan = document.getElementById(itemid).value;
    quan = parseInt(quan) + 1;
    document.getElementById(itemid).value = quan;
    return quan;
}

We'll just mention the parseInt() method in the last snippet of code. As we talked about in the earlier discussion of primitive data types, JavaScript needs to be told explicitly that something is a number and not just a string. parseInt(), or parseFloat() for dealing with floating-point numbers, will convert a string to a numerical value.

Now that you have an updated quantity, you'll probably need to do a couple of things. You'll need to update the subtotal, the sales tax calculation, and the total. You can do this really simply:

function upSubTot() {
    var newQuan = inQuan(itemid);
     var subTot = newQuan * Price;
    return subTot;
}

You can set a variable in the upSubTot() function based on the return value of the inQuan() function. Pretty cool, huh?

Flow control

There will likely come a time when you're going to need to do a little more than just plain mathematics, or string manipulation. You might need to build in some if/then statements in order to handle different scenarios, or you may need to loop over a set of values. Either way, we've got you covered.

If, else if, else

An if statement will check to see whether some condition that you specify is true and will then execute. Let's continue the shopping cart example from earlier in the chapter. Let's say you need to put a limit on the number of a particular item that a single individual can order. Using a simple if statement, you could do this:

function inQuan(itemid) {
    var quan = document.getElementById(itemid).value;
    if (quan <= 5) {
        quan = parseInt(quan) + 1;
        document.getElementById(itemid).value = quan;
    }
    return quan;
}

Now, the quantity will augment only if it's fewer than or equal to 5 units. You can check multiple criteria by using either && (AND) or || (OR):

if ((quan <= 5) || (3 == 2))

This is a bit of a bogus example, because the second condition will never evaluate as true, so it does the same thing as the initial example. If you had replaced the || with &&, the code within the if statement would never get executed because 3 will never equal 2 (at least, not in this universe).

One thing worth mentioning is that unlike other programming languages, in JavaScript the assertions in an OR if statement are evaluated in sequence, not simultaneously. So if the first condition evaluates true, the second condition won't even be tested. You're probably thinking "who cares?" but it's actually possible to have functions serve as your assertions in an if statement (as long as those functions return a Boolean). If your function is doing something else, that something else just won't run.

You're probably wondering what will happen if you try to augment it over the 5-unit limit. Well, currently nothing, so let's build in some code to handle that:

function inQuan(itemid) {
    var quan = document.getElementById(itemid).value;
    if (quan <= 5) {
        quan = parseInt(quan) + 1;
        document.getElementById(itemid).value = quan;
    } else {
        alert("Hey, limit five per customer buddy!");
    return quan;
}

Now, if your customer tries to up the quantity to more than 5 units, they'll receive a JavaScript alert that politely reminds them of your policy. You can go even further, by maybe giving your customer some advance notice of that five-item limit:

function inQuan(itemid) {
    var quan = document.getElementById(itemid).value;
    if (quan < 4) {
        quan = parseInt(quan) + 1;
        document.getElementById(itemid).value = quan;
    } else if (quan < 5) {
        quan = parseInt(quan) + 1;
        document.getElementById(itemid).value = quan;
        alert("You can only have one more before we cut image
        you off!");
    } else {
        alert("Hey, limit five per customer buddy!");
    return quan;
}

Another way to handle if, else if, and else-type of situations is to use a switch statement:

switch(quan) {
case 4:
quan = parseInt(quan) + 1;
    document.getElementById(itemid).value = quan;
    alert("You can only have one more before we cut image
    you off!");
    break;
case 5:
    alert("Hey, limit five per customer buddy!");
    break;
default:
    quan = parseInt(quan) + 1;
    document.getElementById(itemid).value = quan;
    break;
}

So, you can see the logic changes a little here, but the code is generally the same. You pass the switch statement your quan variable. Each of the case statements is then compared to that variable, so the first one checks to see whether quan is equal to 4. If it is, it delivers the warning message and augments the value. The second case statement checks to see whether the quan variable is already equal to 5. If it is equal to 5, you get the cut-off alert. Finally, the default case is just what happens if neither of the other two cases applies.

Loops

You know what they say; the best way to learn something is through repetition. So, although you're still having trouble with JavaScript, return to the start of this chapter and review the contents. There, you've just created your first while loop! It's pretty much the same thing in JavaScript; the syntax just looks something like this:

var understanding = 0;
var mastery = 10;
var reviewChapter = "";
while (understanding < mastery) {
    reviewChapter = reviewChapter + "Chapter reviewed! ";
    understanding = understanding + 1;
}
alert(reviewChapter);

A while loop works while the statement contained within the parentheses is true. So if you assume that your understanding of JavaScript is starting off at zero and if you assume that to be considered a master you have to achieve a level of ten, you would end up with an alert box with "Chapter reviewed!" repeated ten times.

Now, we'll show you a couple of shortcuts. Having to increment your understanding by 1 unit is a pretty common undertaking (OK, not just increasing our understanding, but incrementing values in general). Because of that, there is JavaScript shorthand for it:

understanding++;

This does the same thing as typing understanding = understanding + 1. It's probably pretty easy to guess how you would do the opposite, which is subtract 1 from the value of understanding (understanding--). Another common function is to take a variable and concatenate some value onto the end of it (as in the reviewChapter line).

reviewChapter += "Chapter reviewed! ";

This will give you the same result; it just saves you a few characters.

But while loops aren't the only game in town; you also have for loops that you can call upon to repeat tasks for you. A for loop takes this general form:

for (var understanding=0; understanding < mastery; image
understanding++)

It essentially encapsulates all the elements you need to make the loop run. It does the same thing as the earlier while loop, just with a little less code (which is a good thing!).

Finally, you have one last option, a do...while loop. It look like this:

do {
    understanding++;
}
while (understanding < mastery);

We wish we could say definitively that while loops are better or faster or use less memory than for loops, or vice versa, but most of what's out there says that they're pretty equal. Especially today, with client machines running multiple-core processors and RAM measured in the gigabytes, it's extremely hard to declare a winner here. http://www.devpro.it/examples/loopsbench/ presents a series of tests running for and while loops and shows you the "winner" in each. Take it with a grain of salt; we're talking about hundredths or thousandths of seconds here. Use whichever makes sense to you and whichever makes your code more readable.

Arrays

There may come a time when you want to store more than just a single, simple value in a variable. Luckily, JavaScript allows you to create lists of values called arrays. Arrays are particularly cool when used in conjunction with loops. For example:

var trees = ["Oak","Elm", "Pine"];
var a_tree;
for (var counter = 0; counter < trees.length;
counter++) {
    a_tree = trees[counter];
    alert(a_tree + " is a tree");
}

We'll just dissect a couple of the new things you can see here in this code. For starters, when you create an array, you have to indicate that it's an array and not just a string with a bunch of commas in it. The square brackets take care of that. Second, in the for loop, you've got it looping until the length of trees. In JavaScript, arrays are objects, and all objects have properties. trees.length() will return 3 because you have defined the array with three items. If you needed to retrieve one of these items, though, you would have to use the index value of that item, and JavaScript assigns the first item in an array an index of zero (that's why you start the counter at zero). It's also important to note that the for loop is running only until the value of counter is less than the length of our array (not less than or equal to), because the length property is 3, but the last item in the array is in the second position.

User interaction: alert, confirm, and prompt

Alert, confirm, and prompt are intrusive ways of interacting with your users (but sometimes intrusive is OK). The built-in alert(), confirm(), and prompt() methods in JavaScript will open a dialog box requiring users to click something before they can proceed. Each method is slightly different in what it does, though.

Alert

An alert will open a dialog box with whatever text you specify. You can pass the alert method a variable or a literal value that will then be displayed with an OK button. That button must be clicked before script execution proceeds (blocking action). We talk a little more about alerts later in the "Debugging" section.

alert("Warning: Nuclear launch detected");

Confirm

The confirm method goes one step further than an alert. It will open a dialog box with both an OK button and a Cancel button. You'll see the confirm method used quite frequently where people are being asked to edit or delete information in a database (as shown in Figure 7-2).

image

Figure 7-2. JavaScript confirm method. Clicking OK returns a true value, whereas clicking Cancel returns false. This functionality can be used to abort some action that the user may have accidentally initiated (such as accidentally clicking Delete).

Prompt

A prompt is similar to an alert and a confirm in that it opens a dialog box requiring input, but it also includes a text box in which some value can be entered. Figure 7-3 shows a JavaScript prompt asking the user to enter their name. Clicking OK returns the value entered, and clicking Cancel returns a null value.

image

Figure 7-3. A prompt receives text (or numeric) input before the user is allowed to proceed.

Event handlers: executing code

At this point, we've covered how to write scripts that do all kinds of cool things, but we haven't covered how you can actually tell those scripts to run. How can you call the function impressSiteVisitor() when that button is clicked? How do you know to check the e-mail address entered into the text field after it has been punched in?

Welcome to the world of event handlers. An event handler watches for an event that takes a certain kind of input and executes functions specified by that handler. Let's take a look at a few different options.

"Automatic" execution

The first two event handlers you'll look at don't actually require any user input beyond normal browsing behavior. JavaScript functions can be called onload or onunload, that is, immediately after an element has finished loading or immediately before a page is unloaded (navigated away from). onload is commonly used to preload images. Like if you're planning on swapping an image during a rollover, you don't want someone to mouse over the button and then wait for the image to load; you want it to be instant.

Form-specific handlers

JavaScript is a powerhouse tool at working with forms. As such, a few event handlers are specific to forms (or used primarily in working with forms). onsubmit is a form event handler that gets called when a form is submitted. It is commonly used in order to validate a form's input (check to make sure that text boxes aren't empty, that valid phone numbers were entered, that sort of thing). With the upsurge in Ajax use, JavaScript functions that were previously called using onsubmit are now being called onblur (when a form field loses focus, as previously discussed in Chapter 6: the Tab key is hit, or the next field in the form is clicked).

onblur gives more of an "instant" feel to form validation, and some usability experts have argued that instant feedback is far better than delaying feedback until a form has been completed in its entirety. On some levels, it makes sense: if your form requires a valid US ZIP code (and you've implemented JavaScript validation to check for it), why wait until someone has gone through and filled out all the fields in a form with their mailing information for Canada (Canada's postal codes are a mixture of letters and numbers)? Why not let your customer know at that point that you won't ship outside the United States, rather than after they've completed the entire registration form?

That said, you just can't do certain things with an onblur. Let's say you've written some really sophisticated form validation that will check the area code from the phone number field against the postal code and cross-reference that with the state selected. This type of validation would be better suited to an onsubmit event handler, because you can't be sure that all data will have been entered until the form is submitted. It's not impossible to do with an onblur; you would just have to write a little extra JavaScript to make sure you have all three values before proceeding, though.

A couple of other event handlers might come in handy when working with forms. onchange gets called when the value of an input field is changed. It's commonly used if you're dynamically populating one selection box based on the selection made in another (for example, having a selection box populated with states if United States is selected as the country, with provinces/territories if Canada is selected).

onfocus is the opposite of the onblur event handler. onfocus is executed when an element is clicked or selected using the Tab key. onclick is a common event handler used with buttons and links. onclick fires when the specified element is clicked with the mouse. You can also apply it to radio buttons or check boxes.

Other event handlers

A couple of other event handlers are commonly used today. The onkeyup event handler is called immediately after a key is released. Some of the "search suggestion" functions you see make an Ajax call using the onkeyup event handler, so as input is received, search terms can be suggested (as shown in Figure 7-4).

image

Figure 7-4. "Smart" Ajax-based searches are starting to pop up online. The JavaScript powering these Ajax calls is using the onKeyUp event handler to produce instant feedback.

onmouseover and onmouseout used to be the way to go for performing rollovers on buttons or links, but they've mostly been replaced with CSS-based solutions (as discussed in Chapter 6). You will still see onmouseover and onmouseout used for displaying things such as inline help (tooltips) and for producing really advanced rollover behavior, where multiple elements on the screen are affected.

Tools and practices to debug code

Wouldn't it be great if you could all write perfect code the first time around? It might happen on occasion, but more often than not, something will be slightly off causing either a syntax error, in which case your JavaScript won't run, or a logic error where you won't experience the behavior you were expecting. Luckily, a bunch of free tools are available that help you debug your code.

Alerts

One of the handiest tools in debugging code is the alert method. alert() will open a dialog box with whatever text (or variable) you specify. So, for example, if you're trying to build a basic calculator in JavaScript and you're taking text box A and adding it to text box B but the result is always coming out wrong, you may want to try outputting any intermediate results with an alert():

<script type="text/javascript">
    function addVals() {
        var numOne = document.getElementById('txtbox1').value;
        alert(numOne);
        var numTwo = document.getElementById('txtbox2').value;
        alert(numTwo);
        var endResult = numOne + numTwo;
        alert(endResult);
    }
</script>
<form method="post" action="doit.php">
      <fieldset>
      <legend>Numbers to add together</legend>
         <input type="text" name="txtbox1" id="txtbox1" value="4" />
         <input type="text" name="txtbox2" id="txtbox2" value="7" />
         <input type="submit" onclick="addVals();" />
      </fieldset>
</form>

We put in some default values here just so that I can explain the example in better detail. We're trying to get these two text boxes to add together, but we keep getting the wrong result. It's so frustrating! What's going on? Is it that the variables aren't being set properly, or is it a problem in the math?

We've dropped in three alerts to give us the value of each variable (numOne, numTwo, and endResult) each step of the way. The first alert tells you 4 (as it should), and the second alert returns 7 (again, as it should). The third alert returns 47 (Figure 7-5). Wait, that's not right! It's just taking the two numbers and treating them like text.

image

Figure 7-5. The result of the attempted addition, displayed as an alert in Firefox

Clearly, this is where the problem is. The example is pretty simple, but this very code could be just one part of a very complex shopping cart application that automatically calculates totals, taxes, and shipping; in this situation, it may not be as obvious where you have a problem in your code.

We won't keep you in suspense any longer. The problem is that the function thinks that the two variables are strings and not numbers. You have to convert your strings to numbers before you can mathematically add them together. Change the variable declarations for numOne and numTwo in the previous code to the following:

var numOne = parseInt(document.getElementById('txtbox1').value);
var numTwo = parseInt(document.getElementById('txtbox2').value);

Using the built-in parseInt() function, we're explicitly saying that these values are integers (if you're dealing with decimals, you'll probably want to use parseFloat() instead). Now you're getting the result you would expect (as shown in Figure 7-6).

image

Figure 7-6. The debugging alert() is now showing the proper value.

Debugging tools

You may have noticed (or not) that a lot of the screenshots taken in this chapter show the Firefox browser. We have a small confession to make: Firefox is not actually our browser of choice on the Mac, but the reason why we've used it here is that it has one of the best sets of tools for debugging JavaScript code.

In addition to having a set of debugging tools built right in, Firefox is also easily enhanced through a series of extensions that are available to download and install. We're going to look at a couple of tools that might save you some hair pulling, especially on hard-to-diagnose Ajax scripts.

Safari and Firefox error consoles

One essential tool that is built into Firefox and Safari is the error console. The error console alerts you to any syntax errors in your code, and it tells you roughly where that error occurred. Sometimes the debugging messages are cryptic, and other times they're spot on for where you've messed something up. Figure 7-7 shows the error console with a common error you'll run into when debugging JavaScript (we missed closing the parentheses on a function).

image

Figure 7-7. The error console saying we've missed closing the parentheses on the alert function on line 14.

Web Developer Toolbar

The Web Developer Toolbar is an essential addition, available as a download from http://addons.mozilla.org. It lets you do things like flip JavaScript on and off (so that you can make sure your pages still function, even without JavaScript enabled). It also allows you to flip CSS on and off to make sure your pages make sense, even to a visitor who is visually impaired.

The Web Developer Toolbar will display all kinds of useful information, from the names of IDs and classes inline to the size of various <div> on a page. In terms of useful JavaScript debugging, the Web Developer Toolbar provides a really handy DOM inspector that lets you drill down through the various elements of a page and see the hierarchy of them (as shown in Figure 7-8).

image

Figure 7-8. The DOM inspector shows you a tree view of the various elements on your page.

All in all, the Web Developer Toolbar is an incredibly handy Swiss Army knife of tools that will help you with everything from visualizing page layout to ensuring that your code validates.

Firebug: Ajax debugging bliss

Debugging an Ajax call can be really tricky. It's hard to tell whether it's the JavaScript, server script, or some problem in your CSS that is causing the trouble. That's where the Firebug extension comes in (it's good for many other things too, such as determining why your page is loading so slowly).

Imagine if you could get a running log file of everything that is taking place on a particular page: what data is being sent to the server, what's being received back, how long each of the files are taking to load, and in what order those files are being loaded. That's exactly what Firebug does for you.

Figure 7-9 shows the Firebug output for a page that makes heavy use of Ajax. This is the Lifestream page of the social networking aggregator, Socialthing (we hope out of beta by the time we go to press). Socialthing does a number of Ajax calls to other websites such as Twitter and Facebook and consolidates all the information it gets back. When so many variables are in play, including a number of different websites, Firebug is an invaluable tool for recognizing bottlenecks.

image

Figure 7-9. Socialthing loads so many files and scripts behind the scenes in order to give you a single, unified view of your social networks. I can't imagine what it would have been like to build an application such as Socialthing without Firebug.

We've covered Firefox-based tools almost exclusively thus far. Opera, makers of the Opera web browser, is working on a set of developer tools that they have code-named Dragonfly. As of this writing, they are currently available as an alpha release at http://www.opera.com/products/dragonfly/, and they offer a lot of the same functionality as the Firefox-based tools we've discussed in this chapter.

The latest release of Safari also features a Develop menu that can be enabled via the Advanced preference pane. Apple has included a Web Inspector (Figure 7-10) that replicates some of the functionality present in the Firefox Firebug extension. Combine this with Drosera (available at http://webkit.org/blog/61/introducing-drosera/), and Safari has a robust set of developer tools available as well.

Even Microsoft Internet Explorer offers some tools to assist developers. There is a developer toolbar available for Internet Explorer 7 at http://msdn.microsoft.com/en-us/ie/, and Microsoft is working on a full stack of developer tools for its upcoming Internet Explorer 8 release.

image

Figure 7-10. The new Web Inspector, present in the latest Safari release, replicates some of the functionality present in the Firefox extensions we covered in this chapter.

JavaScript libraries

Not only do we have a great set of tools for working with JavaScript now, we've also entered an age where a number of really great JavaScript libraries are freely available for your use. We talk a little more about libraries later when we take a look at Ajax in Chapter 9, but they're just such a useful development tool that they're worth mentioning here as well.

You can find JavaScript libraries to help with just about any task you need to perform—from animating page elements to making Ajax calls to adding file-browser and manipulation widgets to your pages.

There could be (and indeed there have been) entire books written about the various JavaScript libraries. We'll recommend Jonathan Snook's book, Accelerated DOM Scripting with Ajax, APIs, and Libraries, as a good starting point. Also be sure to check out the websites and documentation for each of the libraries to gauge their strengths and weaknesses in a particular area:

Summary: a little JavaScript goes a long way

JavaScript really is that magic ingredient that makes your pages feel more interactive and more application-like. Used sparingly and where it makes sense, JavaScript can really enhance the user experience. There is nothing you can do to ensure that your end users will have JavaScript enabled, so ensure you always have a backup plan in place, especially where core functionality is at stake. It's great to add some Ajax to your forms to make them submit without a page refresh, but if that's the only mechanism you have in place, you may be shutting out part of your audience. Always make sure that a form can be submitted without using JavaScript (include an action attribute in the <form> tag), and it's often a good idea to perform a second round of input validation on the server using your scripting language of choice.

Design and develop defensively. Shut off JavaScript in your web browser (either using the Web Developer Toolbar described earlier or using just your browser settings), and try to do all the important things on your website. Can a customer still contact you through your feedback form? Can they still place an order? Can they still navigate and get to your important content? Remember, search engines don't support JavaScript, so if you're relying on it for your website navigation, you will be locking out search engines (unless you provide them with an alternate path).

So, take it easy. Build your website first, and then go back through and ask yourself if a particular function could be improved with a little JavaScript. Keep it tasteful, and keep it accessible.

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

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