Chapter 4. jQuery Web Page Manipulation: Mod the DOM

image with no caption

Just because the page is finished loading doesn’t mean it has to keep the same structure. Back in Chapter 1, we saw how the DOM gets built as the page loads to set up the page’s structure. In this chapter, we’ll look at how to move up and down through the DOM structure and work with element hierarchy and parent/ child relationships to change the page structure on the fly using jQuery.

The Webville Eatery wants an interactive menu

Alexandra, the head chef of the Webville Eatery, has a job for you. She’s been maintaining separate web pages for different versions of her menu: the regular menu and the menu with vegetarian substitutions. She wants you to make one page that will adjust the menu for the restaurant’s vegetarian customers.

image with no caption
image with no caption

Here’s what Alexandra would like you to do.

We want a Go vegetarian button that automatically substitutes the vegetarian options on our web page menu.

Here’s how our substitutions work:

  • We offer no substitutes for our fish entrées, so we need those removed.

  • We offer giant portobello mushrooms as a vegetarian substitute for our hamburgers.

  • We offer tofu as a vegetarian substitute for all of our meat and egg dishes except hamburgers.

  • We’ll need a button that restores the menu to its original state.

P.S. If you can pull it off, we’d also like a leaf icon to show up next to the substituted vegetarian entrees.

I had the web designer email you the files for the current menu so you can get started.

Before we write any jQuery, let’s look at the HTML and CSS files the web designer sent us, and see if their style and structure are up to snuff.

As we’ve seen in each chapter so far, we can help jQuery find elements on web pages more effectively by setting up our HTML and CSS properly. To really make our structure sing, we should add classes and IDs to our style sheet and set our HTML elements’ attributes with the appropriate classes and IDs. This makes selecting elements easier and saves you coding time later on.

For jQuery, selectors aren’t just about controlling the look and feel of your page. Selectors allow jQuery to match (or query) elements on the page, too.

image with no caption
image with no caption

Now that you’ve got things mostly set up, let’s go back to the napkin with the head chef’s requirements. Next up, you need to build two buttons.

— We want a Go vegetarian button that automatically substitutes the right vegetarian option on our web page menu.

— We’ll need a second button that restores the menu to its original state.

That was quick! You’ve got the two buttons set up. Let’s check those items off of the napkin and move on to the stuff that the Go vegetarian button needs to do.

— We want a Go vegetarian button that automatically substitutes the right vegetarian option on our web page menu.

— We’ll need a second button that restores the menu to its original state.

Here’s how our substitutions work:

  • We offer no substitutes for our fish entrées, so we need those removed.

  • We offer giant portobello mushrooms as a vegetarian substitute for our hamburgers.

  • We offer tofu as a vegetarian substitute for all of our meat and egg dishes except hamburgers.

Our next task is to tackle item 1 above: match li elements of the fish class and remove them from the menu. We matched elements with class selectors and used remove to take elements out of the DOM in Chapter 2.

jQuery also offers us the detach method. detach and remove both take elements out of the DOM. So what’s the difference between the two methods, and which one should we use?

image with no caption
image with no caption

In Chapter 1, we learned that the DOM is built like a tree. It has a root, branches, and nodes. The JavaScript interpreter in a browser can traverse (and then manipulate) the DOM, and jQuery is especially good at it. DOM traversal simply means climbing up and down and across the DOM.

We’ve been manipulating the DOM since Chapter 1. The detach method we just looked at is an example of DOM manipulation (i.e., we dynamically take elements out of the DOM).

But what is traversal really all about? Let’s take one section of the menu and visualize it as a DOM tree to see how traversal works.

image with no caption
image with no caption

Traversal methods let you select an element and grab other elements above, below, or beside it.

Let’s take a closer look at how you can grab those elements.

To tell the DOM that we want to detach entrées whose menu lists contain fish, we have to reference elements by their relationship. jQuery’s traversal methods allow us to get at those element relationships.

image with no caption
image with no caption

What if we want to climb higher, lower, or deeper? Strap on the chains, man! jQuery offers us method chaining. Method chaining lets us manipulate and traverse our pages in a more effective way. Here’s how it works:

image with no caption
image with no caption
image with no caption

Right. We can’t just detach the fish entrées and forget about them.

We’ll have to rethink our code a bit to make this work.

image with no caption

Variables must be pretty useful because we find ourselves needing them again. We’ve seen variables throughout the first three chapters, but we’ve only used them to store numbers and text strings. Wouldn’t it be convenient if JavaScript variables could store our elements too? As it turns out, they can.

image with no caption

The browser will hold those elements in memory temporarily. If we want to keep them to use in our program later, it’s a good idea to put them into a variable. But how do we do that?

Storing our elements is simple. We create a variable, just as we have for numbers and text strings, and set the variable (using the equals sign) to the statement that returns elements. But wouldn’t it be good to know when the variable is storing special stuff like elements (versus just numbers or text strings)? It’s common practice among jQuery coders to place a dollar sign in front of a variable that will be used to store elements returned from jQuery. That way, anyone else who looks at our code knows that we are using the variable to store stuff that we got from jQuery.

image with no caption
image with no caption

It is messy to store different elements in a variable.

That’s why jQuery uses JavaScript arrays to store elements. Let’s see what arrays are all about.

Any time we select elements from the DOM and store them in a variable, jQuery returns the data as an array. An array is simply a variable with greater storage options.

image with no caption

We can put stuff in and take things out of each storage slot. To put the value “15” into the third slot, we would write this:

image with no caption

When we select and detach the li elements and set a variable ($f) to the result, jQuery takes the elements the DOM returns and stores them neatly for us in a JavaScript array. When we want to put those elements back with the restore button, our job will be way less messy.

$f = $(".fish").parent().parent().detach();
image with no caption

The replaceWith method allows you to replace selected element(s) with new ones. Whenever you want modify the DOM by exchanging one thing for another, you can use this handy jQuery method. Let’s say we want to dynamically change the heading level 2 element that says “Our Menu” to a heading level 1 that says “My Menu.” Here’s how you can do it using the replaceWith method:

image with no caption

You need to match li elements in the hamburger class and replace them with an li element of the portobello class. Let’s think about that problem before we write our code.

image with no caption

What’s next on the checklist?

1.

Match li elements of the fish class and remove those entrées from the menu.

2.

Match li elements in the hamburger class and replace them with portobello mushrooms.

3.

Match li elements in the meat class and replace them with tofu.

You need to find entrées in the meat class and replace them with tofu.

image with no caption

Actually, we can’t use replaceWith for this one.

image with no caption

The replaceWith method works well when you have a one-to-one replacement like exchanging the hamburger class for portbello class.

image with no caption

Up to this point, we’ve either removed or replaced elements in the DOM. Fortunately for us, the creators of the jQuery library gave us many ways to insert stuff into the DOM. The ones we’ll look at are before and after.

before inserts content before the selected element.

image with no caption

after inserts content after the selected element.

image with no caption

You’ve accomplished each of the steps for the Go vegetarian button:

1.

Match li elements of the fish class and remove those entrées from the menu.

2.

Match li elements in the hamburger class and replace them with portobello mushrooms.

3.

Match li elements in the meat class and replace them with tofu.

Up next, we need to build the “Restore Menu” button. Here’s what that button needs to do.

Put the fish entrées back into the menu where we removed them (i.e., before the first menu item in the left column).

Find entrées that contain portobello mushrooms and replace them with hamburger.

Find entrées that contain tofu and replace them with the different kinds of meat (in the right order).

Let’s dig right in and look at what we need to do for the first one.

image with no caption

We know how to use before, but how do we specify the first child?

Fortunately, jQuery provides filtering methods that let us narrow our selection for problems like finding the first child. Let’s look at six of them (three on this page, three on the next).

first

eq

last

The first method will filter out everything but the first element in a selected set of elements.

The eq method will filter out everything but the element whose index number is equal to what you put in the parentheses in a selected set of elements.

The last method will filter out everything but the last element in a selected set of elements.

Let’s look at one item from our menu to see how these methods work:

image with no caption
image with no caption

Now let’s check out the slice, filter, and not methods, and how they work.

slice

filter

not

The slice method will filter out everything but elements with an index between the index numbers you put in its parentheses.

The filter method will filter out everything but elements that match the selector you put in its parentheses.

The not method will filter out everything that does not match the selector you place in the parentheses.

image with no caption

The filter and not methods let us use selectors to create a subset from the matched set using selectors as arguments of their methods.

image with no caption

Which of these methods will help you specify the first child on the menu?

So far for the “Restore Menu” requirement, we’ve got one item down, two to go:

Put the fish entrées back into the menu where we removed them (i.e., before the first menu item in the left column).

Find entrées that contain portobello mushrooms and replace them with hamburger.

Find entrées that contain tofu and replace them with the different kinds of meat (in the right order).

Our next checklist item seems a bit like déjà vu, doesn’t it? All we really need to do is reverse what we did for the original substitution. Why? Because we’re dealing with a one-to-one substitution, and we love one-to-one substitutions because they’re logically simple.

image with no caption

We’re down to our last item for the “Restore Menu” button:

Put the fish entrées back into the menu where we removed them (i.e., before the first menu item in the left column).

Find entrées that contain portobello mushrooms and replace them with hamburger.

Find entrées that contain tofu and replace them with the different kinds of meat (in the right order).

What did we do with those li.meat elements again? Let’s review:

We put li.tofu elements into the DOM after the meat elements.

$(".meat").after("<li class='tofu'><em>Tofu</em></li>");

Then, we detached the li.meat elements but held on to them by saving them into $m.

$m = $(".meat").detach();

So where are those elements, and how do we bring them back?

Remember that whenever we store jQuery elements, we give the variable a dollar sign to signify that the variable we’re using has a special kind of storage. In this case, it’s a jQuery array, and here’s how the elements in $m are stored:

image with no caption

In Chapter 3, you saw how to use the each method to loop through elements. We can use it again here to loop through all the meat elements in the $m array and put them back where they were. But to do that, we’ll need to check out a bit more about how the each method works.

The each method is like an assembly-line machine for your elements.

image with no caption
image with no caption

You did everything required for the “Restore Menu” button. Let’s update our files and call this project done.

Put the fish entrées back into the menu where we removed them (i.e., before the first menu item in the left column).

Find entrées that contain portobello mushrooms and replace them with hamburger.

Find entrées that contain tofu and replace them with the different kinds of meat (in the right order).

P.S. If you can pull it off, we’d also like a leaf icon to show up next to the substituted vegetarian entrées.

image with no caption

Oops, you’re right.

Luckily, the web designer already put the veg_leaf class in the my_style.css file. Let’s have a look at it.

image with no caption

You’ve got Chapter 4 under your belt and now you’ve added DOM manipulation and traversal, arrays, and filters to your toolbox.