This section is about using Ajax to fetch information from the server and inject it into the page.

  1. Ajax Pets
  2. Boot Loader
  3. Chat-It
  4. Pet-It (long)

1. Ajax Pets

Create an AJAX-powered gallery of pet images that allows you to switch between kitty and puppy images without reloading the page. You can view the finished product here.

You are provided with the following HTML file, ajaxpets.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> 
   <head> 
      <title>Pet Gallery</title> 
      <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js" type="text/javascript"></script> 
      <script type="text/javascript" src="ajaxpets.js"></script> 
   </head> 
   <body> 
        <div>
            <label><input type="radio" name="animal" id="kitties" /> Kitties</label>
            <label><input type="radio" name="animal" id="puppies" /> Puppies</label>
        </div>
        <div id="pictures">
        </div>
   </body> 
</html>

You must write a JavaScript file ajaxpets.js which requests data from the https://webster.cs.washington.edu/cse190m/sections/7/ajaxpets/ajaxpets.php script with the parameter animal of value kitty or puppy, depending on which radio button is selected, and injects this into the #pictures div.

Problem by Alex Miller.

Solution

ajaxpets.js:

document.observe("dom:loaded", function() {
   $("puppies").observe("click", updatePictures);
   $("kitties").observe("click", updatePictures);
});

function updatePictures(event) {
    var animal = "";
    if ($("puppies").checked) {
        animal = "puppy";
    } else {
        animal = "kitty";
    }
    new Ajax.Request("ajaxpets.php", 
        {
            method: "get",
            onSuccess: displayPictures,
            parameters: {"animal": animal}
        }
    );
}

function displayPictures(ajax) {
    $("pictures").innerHTML = (ajax.responseText);
}

2. Boot Loader

Given the following HTML skeleton, write the necessary JavaScript code to make an Ajax request to https://webster.cs.washington.edu/cse190m/sections/7/bootloader/loader.php to fetch the URL of an image to display when the 'Load boot' button is clicked, as in this working example.

bootloader.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Boot loader</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/7/bootloader/bootloader.css" />
      <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js"
         type="text/javascript"></script>
      <script type="text/javascript" src="bootloader.js"></script>
   </head>
   
   <body>
      <h1>CSE 190 M Boot Loader</h1>
      
      <div id="container">
         <div id="boot"></div>
      </div>
      
      <div><button id="load">Load boot</button></div>
   </body>
</html>

When the page has finished loading, you should create and inject a loading throbber (like this one) into the #container element along with a message to indicate that data is being loaded. You should use the DOM to create and inject this message, but in HTML it would look like this:

<div id="loading"><img src="loading.gif" alt="Loading..." /> Loading...</div>

Call the Prototype hide method on this loading message initially, before injecting it into the page—then make use of the message later by showing and hideing it as appropriate whenever data is being loaded. You may test this functionality by passing a delay parameter to the loader.php script with an integer number of seconds to wait before responding.

When the server responds with a URL, an image should be created with that src attribute using the DOM and injected into the #boot element. This image should be cleared when a new image is in the process of being loaded.

problem by Morgan Doocy

Solution

bootloader.js

var loading = false;

document.observe('dom:loaded', function() {
   $('load').observe('click', fetchBoot);
   createLoadingMesage();
});

function createLoadingMesage() {
   var throbber = $(document.createElement('img'));
   throbber.src = 'loading.gif';
   
   var div = $(document.createElement('div'));
   div.appendChild(throbber);
   div.innerHTML += 'Loading...';
   div.id = 'loading';
   div.hide();
   $('container').appendChild(div);
}

function fetchBoot() {
   new Ajax.Request('https://webster.cs.washington.edu/cse190m/sections/7/bootloader/loader.php', {
      method: 'get',
      parameters: {
         delay: 1
      },
      onSuccess: displayBoot,
      onFailure: ajaxFailure,
      onException: ajaxFailure
   });
   toggleLoadingMessage();
}

function displayBoot(ajax) {
   toggleLoadingMessage();
   var img = $(document.createElement('img'));
   img.src = ajax.responseText;
   $('boot').appendChild(img);
}

function toggleLoadingMessage() {
   if (loading) {
      $('loading').hide();
   } else {
      $('boot').innerHTML = '';
      $('loading').show();
   }
   loading = !loading;
}

// display a useful error message for debugging purposes (called only if the
// Ajax request did NOT come back successfully)
function ajaxFailure(ajax, exception) {
  alert("Error making Ajax request:" + 
        "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
        "\n\nServer response text:\n" + ajax.responseText);
  if (exception) {
    throw exception;
  }
}

3. Chat-It

Given the following HTML skeleton, write the necessary JavaScript code to make the page into a chat program, as in this working example.

chatit.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf8" />
        <title>Chat-It</title>
        <link href="http://webster.cs.washington.edu/cse190m/sections/7/chatit/chatit.css" type="text/css" rel="stylesheet" />
        <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js"
            type="text/javascript"></script>
        <script src="chatit.js" type="text/javascript"></script>
    </head>
    <body>
        <h1>190M Chat Room</h1>
        <div id="container">
            <div id="messages"> 
            </div>
            <div id="form">
                <input type="text" id="message" value="Type a message..." size="40" /><br />
                <button id="send">Send!</button>
            </div>
        </div>    
    </body>
</html>

Your chat program will make Ajax requests to communicate with a server script (https://webster.cs.washington.edu/cse190m/sections/7/chatit/chatit.php) about two things:

  1. Submitting posts — you should make an Ajax POST request to the above PHP script with the parameter msg in order to submit a post. Make this happen when the 'Post' button is clicked.
  2. Receiving posts — you should periodically (every few seconds) make an Ajax GET request to ask the script for the last 10 posts. Some parameters that can be sent using a GET request: reverse returns the output in reverse-chronological order; limit returns only that many most recent posts; and since takes the Unix timestamp of the last time the client asked for an update, so the script can decide which new posts to send.

Whether sending a GET or POST request, chatit.php will accept a delay parameter to allow you to see a more pronounced delay between requests and responses.

problem by Eli White

Solution

chatit.js

window.onload = function() {
    $('send').observe("click", send);
    
    checkMessages();
    
    setInterval(checkMessages, 2000);
    
    Ajax.Responders.register(
    {
        onFailure: ajaxFailure,
        onException: ajaxFailure
    });
};

function checkMessages() {
    new Ajax.Request("chatit.php",
    {
        method: "get",   
        parameters: {reverse: true}, 
        onSuccess: gotMessages,
    });
}    

function send() {
    new Ajax.Request("chatit.php",
    {
        method: "post",
        parameters: { msg: $("message").value },
        onSuccess: sentMessage,        
    });
}

function sentMessage(ajax) {
   $("message").value = "";
}

function gotMessages(ajax) {   
    var html = ajax.responseText;
    if (html != "") {
        $("messages").innerHTML = html;
    }
}

// display a useful error message for debugging purposes (called only if the
// Ajax request did NOT come back successfully)
function ajaxFailure(ajax, exception) {
    alert("Error making Ajax request:" + 
    "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
    "\n\nServer response text:\n" + ajax.responseText);
    if (exception) {
        throw exception;
    }  
}

4. Pet-It (long)

Today we will write a page "Pet-It" that shows information about breeds of cats and dogs using Ajax. The HTML and CSS are already written; start from the following skeleton:

petit.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <!--
   CSE 190M, Section 7: Pet-It
   original page idea and code by Stefanie Hatcher
   -->
   
   <head>
      <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
      <title>Pet-It</title>

      <link href="http://www.cs.washington.edu/education/courses/cse190m/10su/sections/7/petit.css" type="text/css" rel="stylesheet" />

      <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js" type="text/javascript"></script>
      <script src="petit.js" type="text/javascript"></script>
   </head>
   
   <body>
      <div id="banner">
         <img src="http://www.cs.washington.edu/education/courses/cse190m/10su/sections/7/banner.jpg" alt="Pet-It Banner by Sylvia" />
      </div>
      
      <div id="main">
         <div class="column">
            <img id="pet" src="http://www.cs.washington.edu/education/courses/cse190m/10su/sections/7/puppy.png" alt="cute puppy" />
            
            <ul id="breeds">
               <li>None selected yet.</li>
            </ul>
         </div>
      
         <div class="column">
            <h2>Choose the pet you would like to <q>aw</q> at:</h2>

            <div>
               <label>Dog <input id="dogs" type="radio" name="animal" /></label>
               <label>Cat <input id="cats" type="radio" name="animal" /></label>
            </div>

            <div id="show"></div>
         </div>
      </div>

      <div id="nextblob" class="blob">
         <h1>Next</h1>
         <img id="next" src="http://www.cs.washington.edu/education/courses/cse190m/10su/sections/7/puppy.png" alt="cute puppy" />
      </div>

      <div id="w3c">
         <a href="http://validator.w3.org/check/referer"><img src="http://www.cs.washington.edu/education/courses/cse190m/10su/images/w3c_xhtml11.png" alt="Valid XHTML 1.1" /></a>
         <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="http://www.cs.washington.edu/education/courses/cse190m/10su/images/w3c_css.png" alt="Valid CSS" /></a>
         <a href="https://webster.cs.washington.edu/jslint/?referer"><img src="http://www.cs.washington.edu/education/courses/cse190m/10su/images/jslint.png" alt="JavaScript Lint" /></a>
      </div>
   </body>
</html>

petit.js:

// CSE 190M, Section 7: Pet-It

document.observe("dom:loaded", function() {
    $("dogs").observe("change", getBreeds);
    $("cats").observe("change", getBreeds);
    $("nextblob").observe("click", nextClick);
});

// Part 1: get the list of all breeds of cats/dogs using Ajax
function getBreeds() {
    
}


// Part 3: called when "Next" area is clicked.  Moves to next breed
function nextClick() {
    
}



// provided Ajax failure code
function ajaxFailure(ajax, exception) {
    alert("Error making Ajax request:" + 
        "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
        "\n\nServer response text:\n" + ajax.responseText);
    if (exception) {
        throw exception;
    }
}

Add the JavaScript event-handling and Ajax code. Click the following image to run our sample solution, written by TA Stefanie Hatcher: (solution JS code petit.js)

All required files are on Webster in the directory http://webster.cs.washington.edu/cse190m/sections/7/, or you can download them as section7.zip. Breeds are located in the subdirectory breeds/ relative to the previous URL.

References: Ajax.Request, Ajax.Updater, Ajax options, JSLint

problem Stefanie Hatcher; revised by Marty Stepp

Solution

petit.js

// CSE 190M, Section 7: Pet-It (solution)
// original page idea and code by Stefanie Hatcher

var counter = 0;   // currently selected breed
var breeds = [];   // array of all breed names as strings

document.observe("dom:loaded", function() {
    $("dogs").observe("change", getBreeds);
    $("cats").observe("change", getBreeds);
    $("nextblob").observe("click", nextClick);
});

// Part 1: get the list of all breeds of cats/dogs using Ajax
function getBreeds() {
    var url = this.id + ".txt";
    new Ajax.Request(url, {
        method: "get",
        onSuccess: ajaxListBreeds,
        onFailure: ajaxFailure,
        onException: ajaxFailure
    });
}

// Part 1: displays a list of breeds of animal
function ajaxListBreeds(ajax) {
    $("breeds").innerHTML = "";
    breeds = ajax.responseText.strip().split("\n");
    for (var i = 0; i < breeds.length; i++) {
        var li = document.createElement("li");
        li.id = breeds[i];
        li.innerHTML = breeds[i];
        $("breeds").appendChild(li);
    }
    
    // show the first of the breeds
    displayBreedInfo(0);
}


// Part 2: displays the information about a particular cat/dog breed
function displayBreedInfo(index) {
    // get/display info about the breed
    var url = "breeds/" + convert(breeds[index]) + ".html";
    new Ajax.Updater("show", url, {
        method: "get",
        onException: ajaxFailure,
        onFailure: ajaxFailure
    });
    
    // show the image for the breed
    $("pet").src = "breeds/" + convert(breeds[index]) + ".jpg";

    // Part 3: set up next breed image
    var nextIndex = (index + 1) % breeds.length;
    $("next").src = "breeds/" + convert(breeds[nextIndex]) + ".jpg";

    // Part 3: highlight the name of the currently shown breed
    var allBreeds = $$("#breeds li");
    for (var i = 0; i < allBreeds.length; i++) {
        allBreeds[i].removeClassName("selected");
    }
    $(breeds[index]).addClassName("selected");
}

// Parts 2/3: converts breed such as "Chow Chow" to string such as "chow_chow"
function convert(breed) {
    return breed.toLowerCase().replace(" ", "_");
}

// Part 3: called when "Next" area is clicked.  Moves to next breed
function nextClick() {
    counter = (counter + 1) % breeds.length;
    displayBreedInfo(counter);
}



// provided Ajax failure code
function ajaxFailure(ajax, exception) {
    alert("Error making Ajax request:" + 
        "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
        "\n\nServer response text:\n" + ajax.responseText);
    if (exception) {
        throw exception;
    }
}

Solutions

1. Ajax Pets

ajaxpets.js:

document.observe("dom:loaded", function() {
   $("puppies").observe("click", updatePictures);
   $("kitties").observe("click", updatePictures);
});

function updatePictures(event) {
    var animal = "";
    if ($("puppies").checked) {
        animal = "puppy";
    } else {
        animal = "kitty";
    }
    new Ajax.Request("ajaxpets.php", 
        {
            method: "get",
            onSuccess: displayPictures,
            parameters: {"animal": animal}
        }
    );
}

function displayPictures(ajax) {
    $("pictures").innerHTML = (ajax.responseText);
}

2. Boot Loader

bootloader.js

var loading = false;

document.observe('dom:loaded', function() {
   $('load').observe('click', fetchBoot);
   createLoadingMesage();
});

function createLoadingMesage() {
   var throbber = $(document.createElement('img'));
   throbber.src = 'loading.gif';
   
   var div = $(document.createElement('div'));
   div.appendChild(throbber);
   div.innerHTML += 'Loading...';
   div.id = 'loading';
   div.hide();
   $('container').appendChild(div);
}

function fetchBoot() {
   new Ajax.Request('https://webster.cs.washington.edu/cse190m/sections/7/bootloader/loader.php', {
      method: 'get',
      parameters: {
         delay: 1
      },
      onSuccess: displayBoot,
      onFailure: ajaxFailure,
      onException: ajaxFailure
   });
   toggleLoadingMessage();
}

function displayBoot(ajax) {
   toggleLoadingMessage();
   var img = $(document.createElement('img'));
   img.src = ajax.responseText;
   $('boot').appendChild(img);
}

function toggleLoadingMessage() {
   if (loading) {
      $('loading').hide();
   } else {
      $('boot').innerHTML = '';
      $('loading').show();
   }
   loading = !loading;
}

// display a useful error message for debugging purposes (called only if the
// Ajax request did NOT come back successfully)
function ajaxFailure(ajax, exception) {
  alert("Error making Ajax request:" + 
        "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
        "\n\nServer response text:\n" + ajax.responseText);
  if (exception) {
    throw exception;
  }
}

3. Chat-It

chatit.js

window.onload = function() {
    $('send').observe("click", send);
    
    checkMessages();
    
    setInterval(checkMessages, 2000);
    
    Ajax.Responders.register(
    {
        onFailure: ajaxFailure,
        onException: ajaxFailure
    });
};

function checkMessages() {
    new Ajax.Request("chatit.php",
    {
        method: "get",   
        parameters: {reverse: true}, 
        onSuccess: gotMessages,
    });
}    

function send() {
    new Ajax.Request("chatit.php",
    {
        method: "post",
        parameters: { msg: $("message").value },
        onSuccess: sentMessage,        
    });
}

function sentMessage(ajax) {
   $("message").value = "";
}

function gotMessages(ajax) {   
    var html = ajax.responseText;
    if (html != "") {
        $("messages").innerHTML = html;
    }
}

// display a useful error message for debugging purposes (called only if the
// Ajax request did NOT come back successfully)
function ajaxFailure(ajax, exception) {
    alert("Error making Ajax request:" + 
    "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
    "\n\nServer response text:\n" + ajax.responseText);
    if (exception) {
        throw exception;
    }  
}

4. Pet-It

petit.js

// CSE 190M, Section 7: Pet-It (solution)
// original page idea and code by Stefanie Hatcher

var counter = 0;   // currently selected breed
var breeds = [];   // array of all breed names as strings

document.observe("dom:loaded", function() {
    $("dogs").observe("change", getBreeds);
    $("cats").observe("change", getBreeds);
    $("nextblob").observe("click", nextClick);
});

// Part 1: get the list of all breeds of cats/dogs using Ajax
function getBreeds() {
    var url = this.id + ".txt";
    new Ajax.Request(url, {
        method: "get",
        onSuccess: ajaxListBreeds,
        onFailure: ajaxFailure,
        onException: ajaxFailure
    });
}

// Part 1: displays a list of breeds of animal
function ajaxListBreeds(ajax) {
    $("breeds").innerHTML = "";
    breeds = ajax.responseText.strip().split("\n");
    for (var i = 0; i < breeds.length; i++) {
        var li = document.createElement("li");
        li.id = breeds[i];
        li.innerHTML = breeds[i];
        $("breeds").appendChild(li);
    }
    
    // show the first of the breeds
    displayBreedInfo(0);
}


// Part 2: displays the information about a particular cat/dog breed
function displayBreedInfo(index) {
    // get/display info about the breed
    var url = "breeds/" + convert(breeds[index]) + ".html";
    new Ajax.Updater("show", url, {
        method: "get",
        onException: ajaxFailure,
        onFailure: ajaxFailure
    });
    
    // show the image for the breed
    $("pet").src = "breeds/" + convert(breeds[index]) + ".jpg";

    // Part 3: set up next breed image
    var nextIndex = (index + 1) % breeds.length;
    $("next").src = "breeds/" + convert(breeds[nextIndex]) + ".jpg";

    // Part 3: highlight the name of the currently shown breed
    var allBreeds = $$("#breeds li");
    for (var i = 0; i < allBreeds.length; i++) {
        allBreeds[i].removeClassName("selected");
    }
    $(breeds[index]).addClassName("selected");
}

// Parts 2/3: converts breed such as "Chow Chow" to string such as "chow_chow"
function convert(breed) {
    return breed.toLowerCase().replace(" ", "_");
}

// Part 3: called when "Next" area is clicked.  Moves to next breed
function nextClick() {
    counter = (counter + 1) % breeds.length;
    displayBreedInfo(counter);
}



// provided Ajax failure code
function ajaxFailure(ajax, exception) {
    alert("Error making Ajax request:" + 
        "\n\nServer status:\n" + ajax.status + " " + ajax.statusText + 
        "\n\nServer response text:\n" + ajax.responseText);
    if (exception) {
        throw exception;
    }
}
Valid XHTML 1.1 Valid CSS!