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.
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.
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
.
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.
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 name | Value |
---|---|
accessories |
the currently selected Potato Head accessories as a string, such as "eyes glasses moustache" |
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.
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.
potato2.html
potato.js
(skeleton)
If you did this correctly, the page will show up with no visible accessories, and when you check the checkboxes, nothing will happen.
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>
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.
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
.
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.
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
.