Using an image as a Data Pipe! (Example creates editable data grid!)

Have you ever wanted to accomplish server side tasks without ever leaving the current page? I'm not talking hidden frames, I'm talking about using JavaScript to process cfm templates without ever leaving the page!

How? Simple. Dating back to very early versions of HTML/JavaScript developers were given the ability to dynamically "swap" an image out to accomplish nifty mouseover effects without having to reload the page. Just about any graphical browser can do it, and it's not platform dependent. The image object has a src (source) attribute that tells it what image to display. With a simple JavaScript you can change the src on any event (i.e. onmousover="someimage.src='images/newimage.gif';"). This can fetch any image file from anywhere accessible from that web page without reloading the page.

Now think about this. What if you could use the image.src to call a server-side script template to insert data, query data, build dynamic select fields, save client cookies, validate users or perform any other back-end processing??? You CAN! And much more! With most modern server-side languages such as ASP or CFM you can emulate a content type other than HTML. Using cfheader and/or cfcontent you can return an image content type. So as far as JavaScript and your browser are concerned, it's an image.

Following is a very simplistic yet advanced example of just one of the many uses for this handy method.

TUTORIAL NOTES:

  • This example consists of two files: index.htm and inc_processor.cfm
  • The cfsnippets.mdb database is used in this example
  • This tutorial assumes you have a working knowledge of HTML and JavaScript. (although anyone can learn using copy/paste!)
  • Important code blocks are broken into Code Listing index for easy reference

TUTORIAL GOAL:

To create a simple data grid with the ability to sort, modify and delete records without ever leaving the page!

Section 1 (index.htm)
This is the html page that will have the JavaScript functions to send and receive the data through our image "DataPipe".

<html>
  <head>
  <title>
Simple Data Grid</title>
  <script language="Javascript1.1">
      <!--
      function sendData() {
         //*****************************************
         // Code Listing 1.1
         // This is where we are "swapping" the image for a CFML template. This will
         // be the function fired to start the whole process. Notice that we append
         // the value as url parameters. This may contain multiple url parameters.
         //*****************************************

         document.images.DataPipe.src = "inc_processor.cfm?dsn=cfsnippets&sort=" + radioChecked(document.TestForm.rdoSort);
         //*****************************************
         // Code Listing 1.2
         // The setTimeout function here will make sure our server side script finishes
         // before we call retrieveData(). We only need to do this because we are
         // returning data back from the inc_processor.cfm via cookie. If we were only
         // running a routine with no return data we could call the function directly.
         //*****************************************
       
         TimeOutID = setTimeout("retrieveData()", 100);
      }

      function retrieveData() {

         //*****************************************
         // Code Listing 1.3
         // This function will take the returned values and process them. The values
         // are stored in a cookie called RetVal. In other practical uses you may
         // have multiple name/value pairs returned.
         //****************************************

         // Let's determine the browser. This will help us output the data.
         N=(navigator.appName.indexOf('Netscape')!= -1&&parseInt(navigator.appVersion)<5)
         S =(navigator.appName.indexOf('Netscape')!= -1&&parseInt(navigator.appVersion)>4.9)
         M=(navigator.appName.indexOf('Microsoft')!= -1)

         // Now we are reading the cookie
         var docCookies = document.cookie;
         // Let's initialize a variable to output the finished data
         var cookieOutput = "";

        //*****************************************
        // Code Listing 1.4
        // We need to find the value returned in the cookie. For this example we use
        // RETVAL as our cookie name. If multiple values are returned you would
        // modify this to find each value. For more information on cookies and
        // JavaScript check out:
        // http://devedge.netscape.com/central/javascript/
        //****************************************

        var Pos = docCookies.indexOf("RETVAL=");
        // If the RetVal cookie was not found
        // we wouldn't need to continue.

        if (Pos != -1) {
           // The next two lines determines the starting and ending positions of the
           // cookie value. We will need this to extract the value

           var StartPos = Pos + 7;
           var EndPos = docCookies.indexOf(";",StartPos);
           if (EndPos == -1){
              EndPos = docCookies.length;
           }
           // Now we will extract the value from the cookie.
           var CookieVal = docCookies.substring(StartPos,EndPos);
           // Let's make it pretty.
           CookieVal = unescape(CookieVal);
           CookieVal = CookieVal.replace(/\+/g, " ");

           // This will build a table with the returned data
           cookieOutput = formatOutput(CookieVal);
        }

        //let's show the value.
        if (M){
           test.innerHTML = cookieOutput;
        }else{
           document.getElementById('test').innerHTML = cookieOutput;
        }
      }

      function formatOutput(CookieVal) {
         //*****************************************
         // Code Listing 1.5
         // The purpose of this function is to create a table structure
         // containing the cookie value generated by inc_processor.cfm.
         // This is just an example of how to use returned. Of course
         // in different applications you wouldn't necesarilly need this
         // complexity, but this should give you a good starting point.
         //*****************************************

         var recList = CookieVal.split(",");
         // This is where the table structure will be stored and passed
         // back.

         var cookieOutput = "<table>"
         var i, j;
         var arrRows = new Array;
         var arrCols = new Array
         // Create an array for the field names. This will help us
         // know what field to update in the database when a change
         // is made.

         arrCols[0] = "'emp_id'";
         arrCols[1] = "'firstname'";
         arrCols[2] = "'lastname'";
         //*****************************************
         // Code Listing 1.6
         // Now we need to run through the returned value to extract
         // the data. The value is returned in a two dimensional list.
         // EXAMPLE: "1|Joe|Smith,2|John|Doe,3|Jane|Doe"
         // The comma separated values symbolize a record of data. The
         // pipe separated values are the fields of data in the record.
         //*****************************************

         for (i=0; i<recList.length; i++)
         // Looping through each record.
         {
            // We now extract the field list from the record.
            fldList = recList[i].split("|");
            // We now need to encapsulate the records into table rows.
            cookieOutput = cookieOutput + "<tr>";
            for (j=0; j<fldList.length; j++)
            // Looping through each field in the record
            {
               // Let's put the data into an array. This makes it easy to
               // reference fields within a given record.

               arrRows[i + "," + j] = fldList[j];
               //*****************************************
               // Code Listing 1.7
               // Let's build the cell with the field data. We have decided
               // that the emp_id should not be editable. We know that it is
               // the first value in the record, so we check j, our field counter
               // to make sure it is greater than 0 before we create the form
               // input element. If it is 0 we simply create a <td></td> and insert
               // the value.
               //*****************************************

               var strCell = "<td>";
               if (j > 0){
                  strCell = strCell + "<input type=\"text\" value=\"" + arrRows[i + "," + j] + "\" id=\"fld" + i + "_" + j + "\" name=\"fld" + i + "_" + j + "\" onchange=\"updateRecord(" + arrRows[i + "," + 0] + "," + arrCols[j] + ",this.value);\"></td>";
               }else{
                  strCell = strCell + arrRows[i + "," + j] + ": </td>";
               }
               // Append the new cell to the table structure.
               cookieOutput = cookieOutput + strCell;
            }
            // Append a new cell to the table structure with the delete record button.
            cookieOutput = cookieOutput + "<td><input type=\"button\" onclick=\"deleteRecord(" + arrRows[i + "," + 0] + ")\" value=\"X\"></td></tr>";
         }
         // We are finished creating the table structure. Only thing left to do is
         // append the table's end tag and return the table structure.

         cookieOutput = cookieOutput + "</table>";
         return cookieOutput;
      }
      function deleteRecord(id) {
         //*****************************************
         // Code Listing 1.8
         // This, again is where we are "swapping" the image for a CFML template. We
         // have used different url parameters to tell the template to perform different
         // functions. In this case it will delete a record.
         //*****************************************

         document.images.DataPipe.src = "inc_processor.cfm?del=" + escape(id) + "&dsn=cfsnippets&sort=" + radioChecked(document.TestForm.rdoSort);
         //*****************************************
         // Code Listing 1.9
         // Again we are making sure the template has finished before before we call
         // retrieveData(). We only need to do this because we are returning data back
         // from the inc_processor.cfm to reflect the deleted record.
         //*****************************************

         TimeOutID = setTimeout("retrieveData()", 100);
      }
      function updateRecord(id,fld,val) {<

All ColdFusion Tutorials By Author: Abram Adams