Hooking the Client-­Side Framework to Flickr

Now that you’ve constructed some simple JavaScript code to read form elements and do a calculation in response to a button submission event, you’re ready to wire up a form to use XHR to access the flickrgeo.php server-side proxy. That is, you’ll let the user fill in new values and do the form submission by JavaScript. Once the user hits Go!, the script returns a URL to use flickrgeo.php to search for geotagged photos. We’ll build up the example in three steps:

  1. Translate the form parameters into a query to flickrgeo.php.

  2. Use XHR to do the request to flickrgeo.php and display the resulting JSON response.

  3. Translate that JSON into HTML for display.

Let’s start with the following:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>flickrgeo.1.html</title>
    <meta ?http-?equiv="Content-Type" content="text/html;charset=utf-8" />
  </head>
  <body>
    <script type="text/javascript">
    //<![CDATA[
    function get_pictures() {
    /*
    We're aiming for the following:
    flickrgeo.php?tags=flower&lat0=-90&lon0=-180&lat1=90&lon1=180&page=1&per_page=10&o_format=json
    */
    }
    //]]>
    </script>
    <form action="#" onsubmit="get_pictures(); return false;">
      <label>Search for photos with the following tag:</label>
      <input type="text" size="20" name="tag" value="flower" />
      <label> located at: lat0,lon0,lat1,lon1:</label>
      <input type="text" size="10" name="lat0" value="-90.0" />
      <input type="text" size="10" name="lon0" value="-180.0" />
      <input type="text" size="10" name="lat1" value="90.0" />
      <input type="text" size="10" name="lon1" value="180.0" />
      <label>at page</label>
      <input type="text" size="4" name="page" value="1" />
      <label>with</label>
      <input type="text" size="3" name="per_page" value="1" />
      <label> per page.</label>
      <button type="submit">Go!</button>
    </form>
    <div id="pics"></div>
  </body>
</html>
      

Writing a URL for Querying flickrgeo.php

Your goal is to figure out how to fill in get_pictues() to translate the input parameters from the form into a URL of the correct form. Here’s one possible approach:[139]

 <script type="text/javascript">
 //<![CDATA[
 function get_pictures() {
 // flickrgeo.php?tags=flower&lat0=-90&lon0=-180&lat1=90&lon1=180&page=1&per_page
 // =10&o_format=json
   var s = "";
   f = document.forms[0].getElementsByTagName('input'); // get all input fields
   for (i = 0; i < f.length; i++)
     if (i < f.length - 1) {
       s = s + f[i].name + "=" + escape(f[i].value) + "&amp;";
     } else {
       s = s + f[i].name + "=" + escape(f[i].value);
     }
   var url = "flickrgeo.php?" + s + "&o_format=json";
   document.getElementById('pics').innerHTML = "<a href=" + url + ">URL</a>";
 }
 //]]>
 </script>
         

The get_pictures function iterates through all the <input> tags in the form, extracting the name and value of each tag, out of which to create a URL (with parameters) to flickrgeo.php. This URL is an HTTP GET request for JSON-­formatted results for the given parameters.

Using XHR via the YUI Connection Manager to Read the JSON

The next step is to actually grab the JSON that is available at the URL. Using what you learned earlier (in the section “What Happens with XHR and Direct API Calls”), let’s use the YUI Connection Manager to call flickrgeo.php and display the raw JSON:[140]

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>flickrgeo.2.html</title>
    <meta ?http-?equiv="Content-Type" content="text/html;charset=utf-8" />
    <script type="text/javascript" src="/lib/yui/build/yahoo/yahoo.js"></script>
    <script type="text/javascript" src="/lib/yui/build/event/event.js"></script>
    <script type="text/javascript" src="/lib/yui/build/connection/connection.js">
    </script>
  </head>
  <body>
    <script type="text/javascript">
    //<![CDATA[

    var handleSuccess = function(o){

      div = document.getElementById('pics');
      div.innerHTML = "";  // blank out the div

      if(o.responseText !== undefined){

        div.innerHTML += "Server response: " + o.responseText + "<br/>";
      }

   }

    var handleFailure = function(o){
      if(o.responseText !== undefined){
          alert("failure");
      }
    }

    var callback =
    {
      success:handleSuccess, failure: handleFailure, argument: {}
    };

    function get_pictures() {
    // flickrgeo.php?tags=flower&lat0=-90&lon0=-180&lat1=90&lon1=180&page=1&per_page
    // =10&o_format=json
      var s = "";
      f = document.forms[0].getElementsByTagName('input'); // get all input fields
      for (i = 0; i < f.length; i++)
        if (i < f.length - 1) {
          s = s + f[i].name + "=" + escape(f[i].value) + "&";
        } else {
          s = s + f[i].name + "=" + escape(f[i].value);
        }
      var url = "flickrgeo.php?" + s + "&o_format=json";
      var request = YAHOO.util.Connect.asyncRequest('GET', url, callback);

    }
    //]]>
    </script>
    <form action="#" onsubmit="get_pictures(); return false;">
<label>Search for photos with the following tag:</label>
<input type="text" size="20" name="tags" value="flower" />
<label> located at: lat0,lon0,lat1,lon1:</label>
<input type="text" size="10" name="lat0" value="-90.0" />
<input type="text" size="10" name="lon0" value="-180.0" />
<input type="text" size="10" name="lat1" value="90.0" />
<input type="text" size="10" name="lon1" value="180.0" />
<label>at page</label><input type="text" size="4" name="page" value="1" />
<label>with</label>
<input type="text" size="3" name="per_page" value="1" /><label> per page.</label>
<button type="submit">Go!</button>
    </form>
    <div id="pics"></div>
  </body>
</html>
         

Note what was added:

  • <script> elements to include the relevant parts of the Yahoo! UI Library to enable the use of the Connection Manager.

  • The definition of callback functions (handleSuccess and handleFailure), which are referenced by the callback object, to handle successful and failed calls, respectively, to flickrgeo.php. If the call is successful, the JSON output from flickrgeo.php is written into the <div id="pics"></div>.

  • A call to the Yahoo! Connection Manager in the line var request = YAHOO.util.Connect.?a syncRequest('GET', url, callback);. Remember that an HTTP GET request is made to url and the HTTP response is fed to the functions contained in the callback object.

Converting the JSON to HTML

The next step is to convert the JSON input to HTML so that you can use it to display the photos. Note how you can use eval() to convert the JSON coming back from Flickr to a JavaScript object because you trust the source of this JSON. An alternative to eval() is JSON stringify().[141]

Here’s some code:[142]

<body>
 <script type="text/javascript">
 //<![CDATA[

 function rspToHTML(rsp) {
   var s = "";
   // http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[mstb].jpg
   // http://www.flickr.com/photos/{user-id}/{photo-id}
   s = "total number is: " + rsp.photos.photo.length + "<br/>";

   for (var i=0; i < rsp.photos.photo.length; i++) {
     photo = rsp.photos.photo[i];
     t_url = "http://farm" + photo.farm + ".static.flickr.com/" + photo.server +
       "/" + photo.id + "_" + photo.secret + "_" + "t.jpg";
     p_url = "http://www.flickr.com/photos/" + photo.owner + "/" + photo.id;
     s +=  '<a href="' + p_url + '">' + '<img alt="'+ photo.title + '"src="' +
       t_url + '"/>' + '</a>';
   }
   return s;
 }

 var handleSuccess = function(o){
   div = document.getElementById('pics');
   div.innerHTML = "";  // blank out the div

   if(o.responseText !== undefined){
     div.innerHTML += "Server response: " + o.responseText + "<br/>";

     //let's deposit the response in a global variable
     //so that we can look at it via the shell.
     window.response = o.responseText;
     window.rsp = eval('(' + o.responseText + ')');
     div.innerHTML = rspToHTML(window.rsp);
   }
}

 var handleFailure = function(o){
   ...
 }

 var callback =
 {
   ...
 };

 function get_pictures() {

   ...
 }
 //]]>
 </script>
 <form action="#" onsubmit="get_pictures(); return false;">
   ...
 </form>
 <div id="pics"></div>
</body>
         

You now have a client-­side form that uses XHR to query the Flickr API, get back results in JSON, convert the JSON to HTML, and insert that HTML into the page—without a page reload (see Figure 10-1). The next steps are to integrate these results with Google Maps—the work of the next section.