Chapter 6. The Document Object Model: Web Page Forestry

image with no caption

Wanted: easy-to-update web pages. It’s time to take things into your own hands and start writing code that updates your web pages on the fly. Using the Document Object Model, your pages can take on new life, responding to users’ actions, and you can ditch unnecessary page reloads forever. By the time you’ve finished this chapter, you’ll be able to find, move, and update content virtually anywhere on your web page. So turn the page, and let’s take a stroll through the Webville Tree Farm.

You can change the CONTENT of a page...

So far, most of the apps we’ve built have sent requests, gotten a response, and then used that response to update part of a page’s content.

image with no caption

... or you can change the STRUCTURE of a page

But what if you need to do more than just change the content of a <div> or replace the label on a button? What if an image needs to actually move on a page? How would you accomplish that?

image with no caption

Your users can’t change your XHTML.

The structure of your page is defined in your XHTML, and people viewing your pages definitely can’t mess around with that structure. Otherwise, all the work you’d put into your pages would be a total waste of time.

image with no caption

The browser CAN change your web page’s structure

You’ve already seen that the browser lets you interact with a server-side program, grab elements from a page, and even change properties of those elements. So what about the structure of a page?

Well, the browser can change that, too. In fact, think about it like this: in a lot of ways, the structure of your page is just a property of the page itself. And you already know how to change an object’s properties...

Browsers use the Document Object Model to represent your page

Note

Most people call this the DOM for short.

The browser doesn’t see your XHTML as a text file with a bunch of letters and angle brackets. It sees your page as a set of objects, using something called the Document Object Model, or DOM.

And everything in the DOM begins with the document object. That object represents the very “top level” of your page:

image with no caption

The document object is just an OBJECT

You’ve actually used the DOM, and in particular the document object, several times. Every time you look up an element, you use document:

image with no caption

In fact, every time you treat an element on a page like an object and set properties of that object, you’re working with the DOM. That’s because the browser uses the DOM to represent every part of your web page.

image with no caption

Here’s the XHTML that you write...

When you’re creating a web page, you write XHTML to represent the structure and content of your page. Then you give that XHTML to the browser, and the browser figures out how to represent the XHTML on the screen. But if you want to change your web page using JavaScript, you need to know exactly how the browser sees your XHTML.

Suppose you’ve got this simple XHTML document:

image with no caption

... and here’s what your browser sees

The browser has to make some sense of all that markup, and organize it in a way that allows the browser—and your JavaScript code—to work with the page. So the browser turns your XHTML page into a tree of objects:

image with no caption

Brain Power

How would YOU order and relate these different parts of the DOM tree?

image with no caption

The browser organizes your page into a tree structure, with a root and branches.

When a browser loads an XHTML page, it starts out with the <html> element. Since this is at the “root” of the page, <html> is called the root element.

Then, the browser figures out what elements are directly nested within <html>, like <head> and <body>. These branch out from the <html> element, and they have a whole set of elements and text of their own. Of course, the elements in each branch can have branches and children of their own...until an entire page is represented.

Eventually, the browser gets to a piece of markup that has nothing beneath it, like the text in a <p> element or an <img> element. These pieces of markup with nothing under them are called leaves. So your entire page ends up being one big tree to the web browser.

So let’s look at that tree structure again, but this time, with some lines added to make the connections between the markup a little clearer.

Your page is a set of related objects

image with no caption

Let’s use the DOM to build a dynamic app

Now that we know a bit about the DOM, we can use that knowledge to make our apps do even more interesting things. Let’s take on a project for the Webville Puzzle Company. They’ve been working on a bunch of new web-based games, and they need help with their online Fifteen Puzzle.

image with no caption

We’re not replacing content, we’re moving it

In a Fifteen Puzzle, you can move a tile into the empty space, which then creates a new empty space. Then you can move another tile into that new empty space, and so on. There’s always one empty space, and the goal is to get all the numbers lined up in sequential order, like this:

image with no caption
image with no caption

We need to move those tiles around... and that requires the DOM.

This is a perfect example of needing the DOM. We don’t want to just change the content of a table, or replace some text on a button or in a <p>. Instead, we need to move around the images that represent a tile.

Webville Puzzles is using a table with four rows and four columns to represent their board. So we might need to move an image in the third row, fourth column to the empty space in the third row, third column. We can’t just change the innerHTML property of a <div> or <td> to get that working.

What we need is a way to actually grab an <img>, and move it within the overall table. And that’s where the DOM comes in handy. And, as you’ll soon see, this is exactly the sort of thing that Ajax apps have to do all the time: dynamically change a page.

All Ajax apps need to respond DYNAMICALLY to users.

The DOM lets you CHANGE a page without reloading that page.

Brain Power

What specific steps do you think you’ll have to take to move an <img> from one cell of a table to a different cell?

You start with XHTML...

To really understand how the DOM helps out, let’s take a look at Webville Puzzles’ XHTML, and see what the browser does with that XHTML. Then we can figure out how to use the DOM to make the page do what we want.

image with no caption
image with no caption

Do you want to CHANGE an element or MOVE an element? There’s a big difference.

You could definitely write code that simply swaps out the values of the two <img>’s src properties, like this:

image with no caption

The problem with this is that you’re actually just changing the properties of an image, and not moving those images around on the page.

So what’s the big deal with that? Well, what about the other properties of each image? Remember that each <img> had an alt attribute?

image with no caption

If you change the src attribute, you’re only changing a part of the <img>. The rest would stay the same... and then the alt attribute would not match the image!

image with no caption

What you need to do is swap the entire <img> objects. That way, each <img> keeps its properties. The image doesn’t change, but the location of that <img> in the DOM tree (and on the visual representation of the page) does.

image with no caption

Every node has a parentNode property... but the parentNode property is read-only.

Every node in a DOM tree—that’s elements, text, even attributes—has a property called parentNode. That property gives you the parent of the current node. So for example, the parent node of an <img> in a table cell is the enclosing <td>.

But in the DOM, that’s a read-only property. So you can get the parent of a node, but you can’t set the parent. Instead, you have to use a method like appendChild().

appendChild() adds a new child to a node

appendChild() is a method used to add a new child node to an element. So if you run destinationCell.appendChild(selectedImage), you’re adding the selectedImage node to the children that destinationCell already has:

image with no caption

A new child gets a new parent... automatically

When you assign a node a new child, that new child’s parentNode property is automatically updated. So even though you can’t change the parentNode property directly, you can move a node, and let the DOM and your browser handle changing the property for you.

You can locate elements by name or by id

If you think about your page as a collection of nodes in a DOM tree, methods like getElementById() and getElementsByTagName() make a lot more sense.

You use getElementById() to find a specific node anywhere in the tree, using the node’s id. And getElementsByTagName() finds all elements in the tree, based on the node’s tag name.

image with no caption

Watch it!

Watch the “s” in your method names.

getElementById() is Element, without an “s”, because it returns one element. getElementsByTagName is Elements, with an “s”, because it can return more than one element.

Brain Power

What do you think <td> is talking about in the interview above? Are there any functions we’ve written or will write that might need to worry about those “nothing” children that <td> mentioned?

Can I move the clicked tile?

Now that the basic structure is in place, it’s time to get the puzzle working. Since a tile can only be moved to the empty square, the first thing we need to figure out is, “Where’s the empty square?”

For any clicked-on tile, there are six different possibilities for where the empty tile is. Suppose the user clicked the “10” tile on the board below:

image with no caption

You can move around a DOM tree using FAMILY relationships

Suppose you wanted to find out the parent of an <img> or get a reference to the next <td> in a table. A DOM tree is all connected, and you can use the family-type properties of the DOM to move around in the tree.

parentNode moves up the tree, childNodes gives you an element’s children, and you can move between nodes with nextSibling and previousSibling. You can also get an element’s firstChild and lastChild. Take a look:

image with no caption
image with no caption

Use descriptive names for your elements and your id attributes.

When you’re writing XHTML, the element names are already pretty clear. Nobody’s confused about what <div> or <img> means. But you should still use descriptive ids like “background” or “puzzleGrid.” You never know when those ids will show up in your code, and make your code easier to understand... or harder.

The clearer your element names and ids, the clearer your code will be to you and other programmers.

The DOM is great for code that involves positioning and moving nodes around on a page.

A DOM tree has nodes for EVERYTHING in your web page

Most XHTML pages don’t have every element, from the opening <html> to the closing </html> crammed onto one line. That would be a real pain to read. Instead, your page is full of spaces, tabs, and returns (sometimes called “end-of-lines”):

image with no caption

Those spaces are nodes, too

Even though those spaces are invisible to you, the browser tries to figure out what to do with them. Usually they get represented by text nodes in your DOM tree. So a <table> node might have lots of text nodes full of spaces in addition to all the <tr> children you’d expect.

The bad news is that not all browsers do things the same way. So sometimes you get empty text nodes, and sometimes you don’t. It’s up to you to account for these text nodes, but you can’t assume they’ll always be there. Sounds a bit confusing, doesn’t it?

There are some inconsistencies in how browsers treat whitespace. Never assume a browser will always ignore, or always represent, whitespace.

One browser might create a DOM tree for your page that looks like this:

image with no caption

Another browser might create a different DOM tree for the same XHTML:

image with no caption

The nodeName of a text node is “#text”

A text node always has a nodeName property with a value of “#text.” So you can find out if a node is a text node by checking its nodeName:

image with no caption

swapTiles() and cellIsEmpty() don’t take whitespace nodes into account

The problem with our code is that our functions are assuming that the <img> in a table cell is the first child of a <td>:

image with no caption

Did I win? Did I win?

All that’s left is to figure out when a player’s won. Then, every time two tiles are swapped, we can check this function to see if the board is in order. If it is, the player’s solved the puzzle.

Here’s a puzzleIsComplete() function that uses the names of each image to see if all the tiles are in order:

image with no caption

But seriously... did I win?

There’s even a special class that Webville Puzzles put in their CSS for showing a winning animation. The class is called “win,” and when the puzzle is solved, you can set the <div> with an id of “puzzleGrid” to use this class and display the animation.

That means we just need to check if the puzzle is solved every time we swap tiles.

image with no caption
image with no caption

The DOM is just a tool, and you won’t use it all the time... or sometimes, all that much.

You’ll rarely write an application that is mostly DOM-related code. But when you’re writing your JavaScript, and you really need that next table cell, or the containing element of an image, then the DOM is the perfect tool.

And, even more importantly, without the DOM, there’s really no way to get around a page, especially if every element on your page doesn’t have an id attribute. The DOM is just one more tool you can use to take control of your web pages.

In the next chapter, you’re going to see how the DOM lets you do more than just move things around... it lets you create elements and text on the fly, and put them anywhere on the page you want.

The DOM is a great tool for getting around within a web page.

It also makes it easy to find elements that DON’T have an id attribute.

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

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