Chapter 2
In This Chapter
Introducing the Document Object Model
Responding to form events
Connecting a button to a function
Retrieving data from text fields
Changing text in text fields
Sending data to the page
Working with other text-related form elements
JavaScript is fun and all, but it lives in web browsers for a reason: to let you change web pages. The best thing about JavaScript is how it helps you control the page. You can use JavaScript to read useful information from the user and to change the page on the fly.
JavaScript programs usually live in the context of a web page. The contents of the page are available to the JavaScript programs through a mechanism called the Document Object Model (DOM).
The DOM is a special set of complex variables that encapsulates the entire contents of the web page. You can use JavaScript to read from the DOM and determine the status of an element. You can also modify a DOM variable and change the page from within JavaScript code.
The easiest way to get a feel for the DOM is to load a page in Chrome and play around in the console. Follow these steps to get a feel for the DOM:
Most browsers have something like the web developer console used in this example, but Chrome's is very easy to use and comes built-in, so you should begin with that one.
It's probably easiest to start with a page that's relatively simple, so you can get a sense of what's happening.
Use the F12 key, View ⇒ Developer ⇒ Developer Tools or Tools ⇒ Developer Tools from the menu. (It may vary based on your version of Chrome or your operating system.)
The Developer Tools window has many tabs, but the console tab is the one we need for now (and it will continue to be useful as you get more advanced).
Don't forget the period at the end. When you type a period, Chrome's auto-complete describes all the various elements related to the document. document is a very fancy variable (called an object) that contains a ton of sub-variables. You can scroll through this list to see all the things related to document.
Try typing this in the console:
document.body.style.backgroundColor = “green”
You can use this trick to (temporarily) change all kinds of features.
It's fine if you don't know exactly what's going on yet, but use this technique to get a general feel for the complexity of the page and all the interesting things you can do with it.
Figure 2-1 illustrates a simple web page being dynamically modified through the console tab.
When you look over the DOM of a simple page, you can easily get overwhelmed. You'll see a lot of variables listed. Technically, these variables are all elements of a special object called window. The window object has a huge number of subobjects, all listed in the DOM view. Table 1 describes a few important window variables.
Table 2-1 Primary DOM Objects
Variable |
Description |
Notes |
document |
Represents HTML page |
Most commonly scripted element |
location |
Describes current URL |
Change location.href to move to a new page |
history |
A list of recently visited pages |
Access this to view previous pages |
status |
The browser status bar |
Change this to set a message in the status bar |
It all gets fun when you start to write JavaScript code to access the DOM. Take a look at blue.html in Figure 2-2.
The page has white text on a blue background, but there's no CSS! Instead, it has a small script that changes the DOM directly, controlling the page colors through code.
<!DOCTYPE html>
<html lang = "en-US">
<head>
<meta charset = "UTF-8">
<title>blue.html</title>
</head>
<body>
<h1>I've got the JavaScript Blues</h1>
<script type = "text/javascript">
// use javascript to set the colors
document.body.style.color = "white";
document.body.style.backgroundColor = "blue";
</script>
</body>
</html>
The page shown in Figure 2-3 is pretty simple, but it has a few unique features.
When the browser first sees the script, there must be a body for the text to change. If I put the script in the head, no body exists when the browser reads the code, so it gets confused. If I place the script in the body, there is a body, so the script can change it. (It's really okay if you don't get this discussion. This example is probably the only time you'll see this trick because I show a better way in the next example.)
Of course, there's no good reason to write code like blue.html. You will find that it's just as easy to build CSS as it is to write JavaScript. The advantage comes when you use the DOM dynamically to change the page's behavior after it has finished loading.
Figure 2-3 shows a page called backgroundColors.html.
The page is set up with the default white background color. It has two buttons on it, which should change the body's background color. Click the Blue button, and you see that it works, as verified in Figure 2-4.
Some really exciting things just happened.
Here's the code:
<!DOCTYPE html>
<html lang = "en-US">
<head>
<meta charset = "UTF-8">
<title>backgroundColors</title>
</head>
<body>
<h1>Click a button to change the color</h1>
<form action = "">
<fieldset>
<input type = "button"
value = "blue"
onclick = "document.body.style.backgroundColor = 'blue'"/>
<input type = "button"
value = "white"
onclick = "document.body.style.backgroundColor = 'white'" />
</fieldset>
</form>
</body>
</html>
The buttons work, but the program seems quite inefficient. First, buttons can only have one line of code attached to the onclick event handler. Secondly, the code is almost exactly the same in both buttons. There must be a more efficient way. Most of the time, JavaScript code is not done one line at a time. Instead, it is packaged into a special element called a function. Functions are simply a collection of code lines with a name. Functions can also be sent an optional parameter, and they can return output. You learn much more about functions in Chapter 4 of this minibook, but look at this basic version for now.
<!DOCTYPE html>
<html lang = "en-US">
<head>
<meta charset = "UTF-8">
<title>backgroundColors</title>
<script type = "text/javascript">
// from backgroundColors
function makeBlue(){
document.body.style.backgroundColor = "blue";
} // end changeColor
function makeWhite(){
document.body.style.backgroundColor = "white";
}
</script>
</head>
<body>
<h1>Click a button to change the color</h1>
<form action = "">
<fieldset>
<input type = "button"
value = "blue"
onclick = "makeBlue()"/>
<input type = "button"
value = "white"
onclick = "makeWhite()" />
</fieldset>
</form>
</body>
</html>
This program looks and acts exactly like the program in Figures 2-3 and 2-4, so I don't provide a screenshot here. The important thing is how I've improved the code underneath the visible part of the page.
Something interesting is happening here. Take a look at how this program has changed from the first one.
The function keyword allows you to collect one or more commands and give them a name. In this case, I'm giving that nasty document.body.style nonsense a much more sensible name — makeBlue().
Whenever you define a function, you have to include parentheses, but sometimes (as in this simple example), they're empty. You see how to add something to the parentheses in the next example.
Mark a function with squiggle braces ({}). This example has only one line of code in the function, but you can have as many code lines as you want.
Functions are used to simplify code, so it's really important that a function name describes what the function does.
One button makes the background blue, and the other makes it white, so I'll make a function to go with each button.
Now the buttons each call a function rather than doing the work directly.
The version of the code that uses functions doesn't seem a lot easier than adding the code directly, and it isn't. But functions are much more powerful than simply renaming a line of code. If you think about the two functions in that example, you quickly realize they're almost exactly the same. It would be awesome if you could write one simple function and have it change the background to any color you want. That's exactly what happens in the next example (backgroundColorFunction.html). Here's the code:
<!DOCTYPE html>
<html lang = "en-US">
<head>
<meta charset = "UTF-8">
<title>backgroundColors</title>
<script type = "text/javascript">
// from backgroundColors
function changeColor(color){
document.body.style.backgroundColor = color;
} // end changeColor
</script>
</head>
<body>
<h1>Click a button to change the color</h1>
<form action = "">
<fieldset>
<input type = "button"
value = "blue"
onclick = "changeColor('blue')"/>
<input type = "button"
value = "white"
onclick = "changeColor('white')" />
</fieldset>
</form>
</body>
</html>
Once again, this program will seem to the casual user to be exactly like the programs in Figures 2-3 and 2-4, so I'm not including a screen shot. This is an important part of computer programming. Often the most important changes are not visible to the user. If you've ever hired a programmer, you're no doubt aware of this issue.
function changeColor(color){
The term color inside the parentheses is called a parameter. A parameter is a value sent to a function. Inside the function, color is available as a variable. When you call a function, you can send a value to it, like this:
changeColor('white'),
This sends the text value ‘white’ to the function, where it becomes the value of the color variable.
You'll sometimes see the terms argument and parameter used interchangeably to reference the stuff passed to a function, but these terms are not exactly the same. Technically, the parameter is the variable name (color) and the argument is the value of that variable (‘white’).
You can design a function with as many parameters as you wish, but you need to name each one. After a function is designed with parameters, you must supply an argument for each parameter when you call the function.
Take a careful look at the onclick lines in the code in the preceding section. You may not have noticed one important issue:
onclick is an HTML parameter, and its value must be encased in quotes. The parameter happens to be a function call, which sends a string value. String values must also be in quotes. This setup can become confusing if you use double quotes everywhere because the browser has no way to know the quotes are nested. Look at this incorrect line of code:
onclick = "changeColor("white")" />
HTML thinks the onclick parameter contains the value "changeColor(" and it will have no idea what white")" is.
Fortunately, JavaScript has an easy fix for this problem. If you want to embed a quote inside another quote, just switch to single quotes. The line is written with the parameter inside single quotes:
onclick = "changeColor('white')" />
The changeColor() function is pretty easy to write.
<script type = "text/javascript">
// from backgroundColors
function changeColor(color){
document.body.style.backgroundColor = color;
} // end changeColor
//
</script>
It goes in the header area as normal. It's simply a function accepting one parameter called color. The body's backgroundColor property is set to color.
Perhaps the most intriguing application of the DOM is the ability to let the user communicate with the program through the web page, without all those annoying dialog boxes. Figure 2-5 shows a page with a web form containing two textboxes and a button.
When you click the button, something exciting happens, demonstrated by Figure 2-6.
Clearly, form-based input and output is preferable to the constant interruption of dialog boxes.
Graphic user interfaces usually use a technique called event-driven programming. The idea is simple.
In web pages, the user interface is usually built of HTML and CSS.
If you have a button, users will click it. (If you want to guarantee they click it, put the text “Launch the Missiles” on the button. I don't know why, but it always works.) Buttons almost always have events. Some other elements do, too.
For each event you want to test, write a function that does whatever needs to happen.
Now you're accessing the contents of form elements to get information from the user. You need a mechanism for getting information from a text field and other form elements.
For this simple example, I also use form elements for output. The output goes in a second textbox, even though I don't intend the user to type any text there.
The first step in building a program that can manage text input and output is to create the HTML framework. Here's the HTML code:
<!DOCTYPE html>
<html lang = "en-US">
<head>
<meta charset = "UTF-8">
<title>textBoxes.html</title>
<script type = "text/javascript">
// from textBoxes.html
function sayHi(){
var txtName = document.getElementById("txtName");
var txtOutput = document.getElementById("txtOutput");
var name = txtName.value;
txtOutput.value = "Hi there, " + name + "!"
} // end sayHi
</script>
<link rel = "stylesheet"
type = "text/css"
href = "textBoxes.css" />
</head>
<body>
<h1>Text Box Input and Output</h1>
<form action = "">
<fieldset>
<label>Type your name: </label>
<input type = "text"
id = "txtName" />
<input type = "button"
value = "click me"
onclick = "sayHi()"/>
<input type = "text"
id = "txtOutput" />
</fieldset>
</form>
</body>
</html>
As you look over the code, note a few important ideas:
After you set up the HTML page, the function becomes pretty easy to write because you've already identified all the major constructs. You know you need a function called sayHi(), and this function reads text from the txtName field and writes to the txtOutput field.
HTML is one thing, and JavaScript is another. You need some way to turn an HTML form element into something JavaScript can read. The magical getElementById() method does exactly that. First, look at the first two lines of the sayHi() function (defined in the header as usual).
function sayHi(){
var txtName = document.getElementById("txtName");
var txtOutput = document.getElementById("txtOutput");
You can extract every element created in your web page by digging through the DOM. In the old days, this approach is how we used to access form elements. It was ugly and tedious. Modern browsers have the wonderful getElementById() function instead. This beauty searches through the DOM and returns a reference to an object with the requested ID.
A reference is simply an indicator where the specified object is in memory. You can store a reference in a variable. Manipulating this variable manipulates the object it represents. If you want, you can think of it as making the textbox into a variable.
Note that I call the variable txtName, just like the original textbox. This variable refers to the text field from the form, not the value of that text field. After I have a reference to the text field object, I can use its methods and properties to extract data from it and send new values to it.
After you have access to the text fields, you can manipulate the values of these fields with the value property:
var name = txtName.value;
txtOutput.value = "Hi there, " + name + "!"
Text fields (and, in fact, all input fields) have a value property. You can read this value as an ordinary string variable. You can also write to this property, and the text field will be updated on the fly.
This code handles the data input and output:
This is an ordinary string variable.
Now that you have a variable representing the textbox, you can access its value property to get the value typed in by the user.
Use ordinary string concatenation.
You can also write text to the value property, which changes the contents of the text field on the screen.
Form elements are great for getting input from the user, but they're not ideal for output. Placing the output in an editable field really doesn't make much sense. Changing the web document is a much better approach.
The DOM supports exactly such a technique. Most HTML elements feature an innerHTML property. This property describes the HTML code inside the element. In most cases, it can be read from and written to.
Figure 2-7 shows a program with a basic form.
This form doesn't have a form element for the output. Enter a name and click the button, and you see the results in Figure 2-8.
Amazingly enough, this page can make changes to itself dynamically. It isn't simply changing the values of form fields, but changing the HTML.
To see how the page changes itself dynamically, begin by looking at the HTML body for innerHTML.html:
<body>
<h1>Inner HTML Demo</h1>
<form action = "">
<fieldset>
<label>Please type your name</label><p>
<input type = "text"
id = "txtName" />
<button type = "button"
onclick = "sayHi()">
Click Me
</button>
</fieldset>
</form>
<div id = "divOutput">
Watch this space.
</div>
</body>
The code body has a couple of interesting features:
The JavaScript code for modifying innerHTML isn't very hard:
<script type = "text/javascript">
//from innerHTML.html
function sayHi(){
txtName = document.getElementById("txtName");
divOutput = document.getElementById("divOutput");
name = txtName.value;
divOutput.innerHTML = "<em>" + name + "</em>";
divOutput.innerHTML += " is a very nice name.";
}
</script>
The first step (as usual with web forms) is to extract data from the input elements. Note that I can create a variable representation of any DOM element, not just form elements. The divOutput variable is a JavaScript representation of the DOM div.
Like form elements, divs have other interesting properties you can modify. The innerHTML property allows you to change the HTML code displayed by the div. You can put any valid HTML code you want inside the innerHTML property, even HTML tags. Be sure that you still follow the HTML rules so that your code will be valid.
When you know how to work with text fields, you've mastered about half of the form elements. Several other form elements work exactly like text fields, including these:
Figure 2-9 is a page with all these elements available on the same form.
When the user clicks the button, the contents of all the fields (even the password and hidden fields) appear on the bottom of the page, as shown in Figure 2-10.
Here's the HTML (otherText.html) that generates the form shown in Figures 2-9 and 2-10:
<body>
<h1>Text Input Devices</h1>
<form action = "">
<fieldset>
<label>Normal Text field</label>
<input type = "text"
id = "txtNormal" />
<label>Password field</label>
<input type = "password"
id = "pwd" />
<label>Hidden</label>
<input type = "hidden"
id = "hidden"
value = "I can't tell you" />
<textarea id = "txtArea"
rows = "10"
cols = "40">
This is a big text area.
It can hold a lot of text.
</textarea>
<button type = "button"
onclick = "processForm()">
Click Me
</button>
</fieldset>
</form>
<div id = "output">
</div>
</body>
The code may be familiar to you if you read about form elements in Book I, Chapter 7. A few things are worth noting for this example:
After you build the form, all you need is a function. Here's the good news: JavaScript treats all these elements in exactly the same way! The way you handle a password, hidden field, or text area is identical to the technique for a regular text field (described under “Managing Text Input and Output,” earlier in this chapter). Here's the code:
// from otherText.html
function processForm(){
//grab input from form
var txtNormal = document.getElementById("txtNormal");
var pwd = document.getElementById("pwd");
var hidden = document.getElementById("hidden");
var txtArea = document.getElementById("txtArea");
var normal = txtNormal.value;
var password = pwd.value;
var secret = hidden.value;
var bigText = txtArea.value;
//create output
var result = ""
result += "<dl>
";
result += " <dt>normal</dt>
";
result += " <dd>" + normal + "</dd>
";
result += "
";
result += " <dt>password</dt>
";
result += " <dd>" + password + "</dd>
";
result += "
";
result += " <dt>secret</dt>
";
result += " <dd>" + secret + "</dt>
";
result += "
";
result += " <dt>big text</dt>
";
result += " <dd>" + bigText + "</dt>
";
result += "</dl>
";
var output = document.getElementById("output");
output.innerHTML = result;
} // end function
The function is a bit longer than the others in this chapter, but it follows exactly the same pattern: It extracts data from the fields, constructs a string for output, and writes that output to the innerHTML attribute of a div in the page.
The code has nothing new, but it still has a few features you should consider:
When you run the program in the preceding section, your JavaScript code actually changes the page it lives on. The code that doesn't come from your server (but is created by your program) is sometimes called generated source. The generated code technique is powerful, but it can have a significant problem. Try this experiment to see what I mean:
You want to view it without the form contents showing so that you can view the source. Everything will be as expected; the source code shows exactly what you wrote.
Your function runs, and the page changes. You clearly added HTML to the output div because you can see the output right on the screen.
You'll be amazed. The output div is empty, even though you can clearly see that it has changed.
Using the HTML validator extension or the W3 validator (described in Book I, Chapter 2) doesn't check for errors in your generated code. You have to check it yourself, but it's hard to see the code!
Figure 2-11 illustrates this problem.
Here's what's going on: The view source command (on most browsers) doesn't actually view the source of the page as it currently stands. It goes back to the server and retrieves the page, but displays it as source rather than rendered output. As a result, the view source command isn't useful for telling you how the page has changed dynamically. Likewise, the page validators check the page as it occurs on the server without taking into account things that may have happened dynamically.
When you build regular web pages, this approach isn't a problem because regular web pages don't change. Dynamically generated pages can change on the fly, and the view source tool doesn't expect that. If you made a mistake in the dynamically-generated HTML, you can't simply view the source to see what you did wrong. Fortunately, Chrome gives you a pretty easy solution.
The Chrome developer tools (available with the F12 or Cmd+shift+I on Mac — have I mentioned how awesome this tool is?) can show you exactly what the browser is currently displaying.
Here's how you can use it:
Click the buttons and do what the page does to modify itself.
Right-click anywhere on the page and choose inspect element from the popup menu. The developer tools will pop up and you'll be in a special outline view.
Select a piece of code in the elements view and the corresponding part of the page is highlighted.
When you're in inspect mode, you can click on any visible element of the page and the corresponding code will be highlighted.
Unlike the view source results, the element inspector shows what's currently on the screen rather than what's on the server.
You can double-click on content in the Elements tab and change it, and the page changes alongside it. (Hmm … does this mean you could change the headlines of an online newspaper and make it look totally real? That seems mischievous. I hope nobody ever does that.) Don't worry. None of the changes are permanent.
You can see exactly what tags are active by looking at the bottom of the developer screen.
As described in Book II, you can also modify the CSS on this screen to see how the page will look if the CSS is changed. This is an ideal way to experiment with the page.
These tools keep you sane when you're trying to figure out why your generated code isn't acting right. (I wish I'd had them years ago….)
Figure 2-12 shows the Chrome developer tools with the dynamically generated contents showing.
If you're using another browser, the Firebug extension does most of the same things as the Chrome developer tools. Firebug performs best on Firefox, but there is a light version which works on any browser.
If none of these tools is available, there's another cool trick you can do. Type the following into the address bar:
javascript:alert(document.body.innerHTML)
This very sneaky trick uses JavaScript to generate the source code of the page as it currently stands:
When you begin an address with javascript, the browser immediately renders the rest of the address as a JavaScript instruction rather than an address. Cool, huh? (Try javascript: alert(2+5) to turn your browser into a calculator. Whoa.)
You want to look at the source of whatever page is currently loaded, so use the alert mechanism to print the code in a pop-up and leave the original page in place.
The document.body.innerHTML trick returns all the HTML code inside the body tag. This doesn't show your header or doctype information, but it does display the page as it currently sits in memory, even if it has been changed dynamically through code. That's usually enough to figure out what's going wrong in a pinch.