Ajax: Sending data to a server

Note: If you don't know about objects and loops, read this and this before going further.

Earlier, we saw how a jQM Web page could request data about a random photo from a server, and display what it got back. The client didn't send data to the server, except for a page request.

Let's take it a step further. Suppose we want to build a photo gallery application. This is more complex than we've seen before, so let's take it slowly.

Data on the server

As before, the file load_image_data.php has the data:

  1. $image_data = array(
  2.   array(
  3.     'file_name' => 'photo1.jpg',
  4.     'description' => 'Dudes in boaters',
  5.   ),
  6.   array(
  7.     'file_name' => 'photo2.jpg',
  8.     'description' => 'Lectures haven\'t changed',
  9.   ),
  10.   array(
  11.     'file_name' => 'photo3.jpg',
  12.     'description' => 'Halloween',
  13.   ),
  14.   array(
  15.     'file_name' => 'photo4.jpg',
  16.     'description' => 'Hot chick',
  17.   ),
  18.   array(
  19.     'file_name' => 'photo5.jpg',
  20.     'description' => 'Woodrow Wilson, vampire',
  21.   ),
  22.   array(
  23.     'file_name' => 'photo6.jpg',
  24.     'description' => 'Giants examine a ship',
  25.   ),
  26. );

$image_data is a nested array. It has six elements. Their indexes range from [0] to [5].

Just one

First, let's make a simple client that gets just one photo from the server. You can try it, and download the zip.

Here's how the app will look, at the start:

Get one photo

The user types in an id, and clicks the button. The app shows that it's waiting for the server:

Spinny thing

Once the server responds, the client shows the result:

Result

Here's the code for the form.

  1. <label for="basic">Photo id:</label>
  2. <input type="text" name="id" id="id" value=""  />    
  3. <p><a id="show-button" href="#" data-role="button">Show photo</a></p>
  4. <p id="description"></p>
  5. <p><img id="photo"></p>

Line 2 is the input field, and line three is the button. Lines 4 and 5 start off MT. Later, they're filled with data from the server.

Here's JavaScript from the client, run when the user clicks the button:

  1. $("#show-button").click(function(){
  2.   //Erase what is showing.
  3.   $("#description").html("");
  4.   $("#photo").attr("src", "");
  5.   $.getJSON(
  6.       "../server/fetch_photo.php?id=" + $("#id").val(),
  7.       function( photo ) {
  8.         var file_name = photo.file_name;
  9.         var description = photo.description;
  10.         $("#description").html(description);
  11.         $("#photo").attr("src", "../server/images/" + file_name);
  12.         //Put cursor in input field.
  13.         $("#id").select();
  14.       }
  15.   )
  16. });

It's the same as before, except for line 6:

"../server/fetch_photo.php?id=" + $("#id").val()

fetch_photo.php is the server script. The client has to tell the server which photo the user wants to see. There are various ways to do this, but the easiest is to attach data to the end of the URL, like this:

fetch_photo.php?id=3

You can send more than one field. For example:

record_score.php?michgan=48&msu=0

The & separates the fields.

If you want to send spaces, replace them with +s:

send_pizza.php?address=1600+Pennsylvania+Avenue

This is an example of URL encoding. URLs should only contain letters and numbers, and a few characters that have special meaning, like & and +. What if you want to send $, ), ©, or Æ? You URL encode them. We don't need to worry about that here, but it will come up later on in the course.

Simple server

Here's pseudocode for the server:

Load the photo data.

Get the photo id from the client.

Return the data for the photo with that id.

Here's the PHP:

  1. //Wait for a second. Simulates processing delay.
  2. sleep(1);
  3. //Load the data array.
  4. require( 'load_image_data.php' );
  5. //Get the id of the photo to look up.
  6. $photo_number = $_GET['id'];
  7. //Return data about the random photo.
  8. echo json_encode(
  9.     array(
  10.       'file_name' => $image_data[ $photo_number ][ 'file_name' ],
  11.       'description' => $image_data[ $photo_number ][ 'description' ],
  12.     )
  13. );

The key is line 6:

$photo_number = $_GET['id'];

This will get data from the URL parameter id, and put it into the variable $photo_number. Lines 10 and 11 use the value as an index into the data array.

Commands

This works, but isn't very useful. Let's make it more real.

Geeks talk about application program interfaces, or APIs. APIs are sets of rules that programs use to interact.

We've just created an API. Let's call it CRAPI Reprehensible API (CRAPI), and document it like this:

Call fetch_photo.php. Send it a photo id. For example: fetch_photo.php?id=4

Return value: JSON data structure:

file_name: Name of the file with the given id.

description: Description of the file with the given id.

(CRAPI is a recursive acronym. Geeks think they're funny. Keith is LOLling right now.)

The API is a contract betwixt client and server. The client doesn't need to know how the server works. Maybe the data comes from a database, or a ouija board. All the client needs to know is (1) what data to send, and (2) what data it will receive.

APIs are critically important in computing. Standardized APIs let different company's products work together. For example, I use the graphics software GIMP. GIMP can read data from any scanner that uses TWAIN, an API (and other things) for data acquisition. I have an Epson scanner, but I could use one from HP, or someone else. As long as a scanner is TWAINy, I can use it.

Suppose you wanted to make the Light Extension Software Susurration CRAPI, or LESSCRAPI. CRAPI has just one action: get a photo. You want LESSCRAPI to have two actions:

  • Get the number of photos.
  • Get a photo.

You could have two different URLs, like this:

  • Get the number of photos: call get_num_photos.php
  • Get a photo: call fetch_photo.php

Another way you could implement LESSCRAPI is to have one URL, and send it different commands:

  • Call photo_server.php, command = count
  • Call photo_server.php, command = fetch

This is more convenient, since you don't need to create many different pages.

An example of the count command:

photo_server.php?command=count

Count needs no parameters.

An example of the fetch command:

photo_server.php?command=fetch&id=3

Fetch needs one parameter: the id of the photo to fetch.

Gallery app: server

We can use LESSCRAPI to make a better photo gallery app. You can try it, and download it.

As you can see, the app shows all the photos in the gallery.

Here's the server:

  1. <?php
  2. /**
  3.  * Photo server.
  4.  */
  5. //Load the data array.
  6. require( 'load_image_data.php' );
  7. //Get the command.
  8. $command = $_GET['command'];
  9. //Process count command.
  10. if ( $command == 'count' ) {
  11.   //Ah ah, I love to count.
  12.   echo json_encode(
  13.       array(
  14.         'count' => sizeof($image_data),
  15.       )
  16.   );
  17.   exit;
  18. }
  19. //Process fetch command.
  20. if ( $command == 'fetch' ) {
  21.   //Get data about a photo.
  22.   $id = $_GET['id'];
  23.   echo json_encode(
  24.       array(
  25.         'file_name' => $image_data[ $id ][ 'file_name' ],
  26.         'description' => $image_data[ $id ][ 'description' ],
  27.       )
  28.   );
  29.   exit;
  30. }
  31. echo json_encode(
  32.     array(
  33.       'error' => 'Unknown command',
  34.     )
  35. );
  36. exit;

Line 6 loads the data array as usual. Line 8 gets the command. Line 10 tests to see if the command is count. If it is, line 14 returns the number of elements in the data array. Line 17 - exit - stops the server.

Line 20 tests to see if the command is fetch. The server knows that it needs the id of the photo to fetch. Line 22 grabs it. Lines 23 to 28 return the data about the photo with the given id. Line 29 stops the server.

The server script will only get to line 31 if the command wasn't count, and it wasn't fetch. The server returns an error message in that case.

Gallery app: client

The JavaScript client is a little more complex than before. Here some pseudocode:

  1. Ask the server how many photos there are.
  2. Put the returned value in the variable num_photos.
  3. id = 0
  4. Do the following num_photos times:
  5.     Get data about the photo with an id of id.
  6.     Append the photo to the page.
  7.     Add 1 to id.

At the end of this, we'll have a page with all of the photos showing.

Lines 4 to 7 are a loop. That is, the same code is run a number of times. The code does something a little different each time, because the value of id changes each time through the loop.

If you don't know about objects and loops, read this and this before going further.

Here's the JS:

  1. $.getJSON(
  2.     "../server/photo_server.php?command=count",
  3.     function ( result ) {
  4.       var num_photos = result.count;
  5.       var id;
  6.       //Loop. Repeat some code, changing the value of the variable id
  7.       //each time through. id starts at 0, and ends at num_photos - 1.
  8.       for ( id = 0; id < num_photos; id++ ) {
  9.         $.getJSON(
  10.           "../server/photo_server.php?command=fetch&id=" + id,
  11.           function ( photo ) {
  12.             var photo_html =
  13.                   "<p>" + photo.description + "</p>"
  14.                 + "<p><img src='../server/images/" + photo.file_name + "'></p>";
  15.             $("#output-area").append(photo_html);
  16.           }
  17.         ); //End get.
  18.       } //End for loop.
  19.     }
  20. ); //End get.

Lines 1 and 2 call the server, sending it the command count. When the server comes back with data, line 4 puts the count in the variable num_photos. The photo ids range from 0 to (num_photos - 1).

Line 8 starts a loop. The looping variable is id. It starts at 0, and goes up by one each time through the loop. The loop runs while id < num_photos.

Each time through the loop, line 10 creates a URL that includes the looping variable, id. id is 0, then 1, then 2, and so on. Each time, lines 9 and 10 ask the server for a photo, with the next id in sequence. The data comes back in the variable photo in line 11. Line 12 creates some HTML to show the photo. Line 15 appends that HTML to the end of the body.

Summary

You can send data to the server by appending it to the URL. The server can grab the data, and use it in its own processing.

A common approach to APIs is to define a set of commands. Commands are sent to the same URL, along with data the commands need.