Web Programming Step by Step
Lab 8: Mr. Potato Head (Web Services and Scriptaculous)

original lab idea, code, and images by Victoria Kirst; revised by Brian Le

The purpose of this lab is to practice Scriptaculous and a web service in PHP to save and restore a page's state. We'll make a page that lets the user put accessories on a Mr. Potato Head toy.

Whenever an accessory is added or removed, this information is sent to a PHP web service on the server, which saves the state of which options are checked. When the user comes back to the page later, it restores this state.

expected output

Lab 8 Resources

Exercises for Today:

  1. Download Starter Files, Put Them on Webster
  2. PHP Web Service v1
  3. PHP Web Service v2
  4. Switch Starter Files
  5. JavaScript v1 (Initial Accessories)
  6. JavaScript v2 (Checkbox Toggling)
  7. JavaScript v3 (Save State to Server)

Exercise 0: Download Starter Files, Put Them on Webster (roughly 5 minutes)

First, download the following starter file (right-click the link below) and then upload it to your Webster space. Then direct your browser to the appropriate Webster URL to see the page.

The starter page has all of the JavaScript and Ajax code already written, but is missing its PHP code. If you did this exercise correctly, the page will show up and you'll be able to check/uncheck the boxes, but it will show Ajax error popup messages about "404 not found, potato.php". This is expected for now; next we will fix that.

Exercise 1: PHP Web Service v1 (roughly 5 minutes)

The potato page expects there to be a web service named potato.php that will tell it which accessories to initially check. It tries to contact this service with Ajax. The page expects the service to send back the initial accessories as a plain text string separated by spaces. So far there is no such PHP service, but in this exercise you will write one.

Make a (very short) PHP file potato.php that always outputs a single plain text line containing the text eyes glasses moustache . Upload this to your Webster space in the same folder as your potato.html. Don't forget to set your content type to text/plain.

page Ajax GET request

If you did this exercise right, now when you refresh your potato.html page it should not display Ajax errors, and now the eyes, glasses, and moustache should show up when it first loads. But if you refresh the page, it won't remember which accessories you checked.

Exercise 2: PHP Web Service v2 (Complete) (roughly 15 minutes)

Now write the rest of the PHP web service so that the page saves the state on the server of which accessories are enabled. Every time the user checks or unchecks a box, the page's JavaScript code sends an Ajax POST request to potato.php, telling it what accessories are selected. It sends this information as a query parameter named accessories, whose value is a string containing the names of the selected accessories separated by spaces.

Parameter nameValue
accessories the currently selected Potato Head accessories as a string, such as "eyes glasses moustache"
page Ajax POST request

To make the server save the state correctly, change your PHP code to handle both GET and POST requests. When a POST request arrives, examine the query parameter accessories. Read its value and save it into a file named potato.txt. When a GET request arrives, you should instead read the contents from file potato.txt and send them back as output. If there is no file potato.txt, send back an empty string. Recall the PHP functions file_get_contents and file_put_contents, and file_exists.

If you've completed this exercise correctly, you should be able to check and uncheck accessories, then refresh the page, and it should remember. If it doesn't work, look at the Console tab in Firebug to see each Ajax request made by the page, the parameters passed to it, and the response sent back by the PHP web service.

Exercise 3: Switch Starter Files (roughly 5 minutes)

Now that your PHP web service works, you'll write some of the JavaScript code for the page. In the previous exercises, all of the JavaScript was already written, but we're going to toss that out and rewrite it ourselves. First download the following updated starter files below and upload them to Webster. Point your browser to potato2.html instead of potato.html. (The only difference is that potato2.html links to your own JS file, rather than the already-written solution JS file.) Also, open up potato.js in your editor.

If you did this correctly, the page will show up with no visible accessories, and when you check the checkboxes, nothing will happen.

Exercise 4: JavaScript v1 (Initial Accessories) (roughly 15 minutes)

In this exercise, you'll make it so that the page fetches and displays the initial accessories that have been saved to the PHP web service.

It will be helpful to understand the HTML code in the page. Each checkbox has an id to match its body part, such as ears. Each checkbox is intended to show/hide an image with a similar id such as ears_image. Initially all of the images are hidden.

<fieldset id="controls">
    <legend>Parts</legend>

    <label><input type="checkbox" id="arms" /> Arms</label>
    <label><input type="checkbox" id="ears" /> Ears</label>
    <label><input type="checkbox" id="eyes" /> Eyes</label>
    ...
</fieldset>

<div id="potato">
    <img id="arms_image" src="arms.png" alt="arms" />
    <img id="ears_image" src="ears.png" alt="ears" />
    <img id="eyes_image" src="eyes.png" alt="ears" />
    ...
</div>

Add JS code so that when the page loads, you contact potato.php on the server using Ajax. The response text that comes back should be a string such as "eyes glasses moustache". When the Ajax response arrives, break apart this string and check the appropriate boxes and show the appropriate accessories. The starter JS code contains some functions to help you break apart the string into an array. For example, if the response text contains "hat", you should check the "hat" box and show the "hat_image" image. Use Scriptaculous effects to make the images appear. Recall that you can control whether a checkbox is checked by setting its boolean checked property. Note that the response text may be empty if no accessories are showing; you may need to check for the empty string to avoid an error.

You can also set the page's h2 heading to show the state of what the potato head is wearing. This heading has an id of status.

<h2 id="status">He is wearing: </h2>

Exercise 5: JavaScript v2 (Checkbox Toggling) (roughly 15 minutes)

Now add the code to make the checkboxes work. Modify the toggleAccessory event handler so that when a box is checked/unchecked, the appropriate image is shown or hidden on the page. Use Scriptaculous to add an effect when the image appears (such as grow or appear) and disappears (such as fade or shrink). Take advantage of the fact that the id of every image is the same as the id of the corresponding checkbox, but with "_image" appended at the end.

If you've completed this exercise, you should be able to add and remove accessories from Mr. Potato Head. But when you refresh the page, it always reverts to the initial state it had the last time you went to the page.

Exercise 6: JavaScript v3 (Save State to Server) (roughly 10 minutes)

In this final exercise, when the user checks/unchecks any checkbox, save the current state of accessories to the server. Modify your toggleAccessory event handler for checkboxes to do this. We have provided a function getAccessoriesString that examines the checkboxes on the page and builds/returns a string representing which boxes are checked. For example, if checkboxes for eyes, glasses, and moustache are checked, it returns "eyes glasses moustache". Use an Ajax POST request to send this string to the server as a query parameter named accessories.

page Ajax POST request

If you've completed this exercise, you should be able to check and uncheck any accessories you like, and if you refresh the page, the state should be remembered. Congratulations! You've created a stateful Ajax/PHP Web 2.0 application.

Exercise 7 (for l33t h4x0rZ only): More Scriptaculous Effects

If you finish all the preceding exercises, enhance the page by making it possible to move around all of the accessories. Make them Draggable using Scriptaculous. If you're really l33t, modify the PHP service and JavaScript code so that when an image is moved around, the page remembers its position and saves it to the server. You'd have to modify the format of the data saved by the PHP service so that it retains x/y positions of each accessory. It might look something like this:

eyes 123 98 glasses 74 84 moustache 56 251

It may help you to handle the events on the Draggable object such as onStart, onDrag, and onEnd.

Valid XHTML 1.1 Valid CSS!