How to use dBase applications with the Ajax technique
By: Andrew Teller (dBASE R&D)

Table of contents
  1. Purpose
  2. Introduction: What is Ajax?
  3. Initializing the XMLHttpRequest object
  4. Sending a request via the POST method
  5. Sending a request via the GET method
  6. Receiving a request in dBase
  7. Sending a response from dBase
  8. Receiving the server's response
  9. Parsing the server's response
  10. Example application
  11. Appendix A
Purpose
The purpose of this guide to present a small introduction to the Ajax technique and how to use dBase web applications with this technique. You should learn what Ajax is, how to use it to send data to your dBase web applications, how your applications should receive data and send data back to the client, and how the client is to receive and parse the applications response.
This document will assume that you already have a working server capable of running dBase Applications. Our example will assume that your dBase applications are accessible on the web through a 'cgi-bin' folder in the root of your domain. If this is not the case then you will need to change the URLs in the example accordingly.
Introduction: What is Ajax?
Ajax is a technique to perform asynchronous communication between the client and the server through the basic browser system. Asynchronous communication allows the user to continue working while the client and server respond to each other. A web page that implements Ajax should be able to update the content of its page without having to reload the page. This allows your web pages to have the feel of a fuller, thicker, client application.
The Ajax technique uses a combination of existing technologies. Among these are JavaScript, DOM, CSS, XML, and the XMLHttpRequest object. Most of these might be familiar to you with exception to the XMLHttpRequest object. Regardless, all of these technologies are just the client-side solution for Ajax applications. The server-side solution on the other hand is independent of the Ajax method and so Ajax can be used with just about anything you might be familiar with; PHP, ASP, JavaServlet, and, of course, dBase Plus.
Ajax is a term coined by Jesse James Garrett in a 2005 article. The term stands for Asynchronous JavaScript + XML.
Initializing the XMLHttpRequest object
The key to Ajax is the communication between the client browser's current page and the server. This communication is done through the XMLHttpRequest object. This object was originally implemented as an ActiveX control for Internet Explorer. Over the past few years it has also been added to other browsers as a property of the window object. The good news is there is now wide support among browsers, the bad news is that one of the most widely used browsers, Internet Explorer, implements the XMLHttpRequest object differently from everyone else. Luckily, the way to handle this difference isn't all that complicated.
When attempting to initialize an XMLHttpRequest object, all you need to do is check to see if the browser has an ActiveX control object. If so then the browser is Internet Explorer and you should initialize the object as an ActiveX control, otherwise it is another browser and so it's just a property of the window object. After initialization the object works pretty much the same regardless of which one it is. The following is a JavaScript function that implements the described initialization:
function createXMLHttpRequest() {
  if (window.ActiveXObject) {
    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
  }
  else if (window.XMLHttpRequest) {
    xmlHttp = new XMLHttpRequest();
  }
}
This function should be inserted into the header of all our Ajax web pages and will be called before any attempt to communicate with our dBase applications. The 'xmlHttp' variable should be defined outside the function so that it can be used in other functions on our web page.
A list of properties and methods, along with their descriptions, for the XMLHttpRequest object are listed in Appendix A of this document.
The XMLHttpRequest property is available on the window object in Internet Explorer 7.0 and later. Therefore, when 7.0 becomes broadly accepted by IE users you should no longer need to maintain an extra condition in order to instantiate the XMLHttpRequest object. For now though it is safer to leave this function as is.
Sending a request via the POST method
As you may already know, you can send data to a server in one of two methods, GET and POST. They have their differences, but explaining that difference in detail is outside the scope of this document. The method preferred by this article is the POST method. The reason is that the GET method has a limited length of information it can send to the server. Also, any advantage it may have is mostly lost when using the Ajax technique. In regards to your dBase web application, it won't care which way you send it.
Communication via the POST method begins by initializing an XMLHttpRequest object, which can be done through the function described above. The next thing you'll need to do is tell the XMLHttpRequest object what to do once the request is sent and then received. This is done by assigning an event handler. The 'onreadystatechange' property of the XMLHttpRequest object is an event that will trigger whenever the XMLHttpRequest object goes through a state change. You can assign a function to it in much the same way we assign functions to events in dBase. The 'open' method of the XMLHttpRequest object establishes the connection and accepts a number of parameters. Through these parameters you will tell the object what method to use to communicate, what URL to send the request to, and whether or not to send the request asynchronously. Next, specify the header of the request via the 'setRequestHeader' method and finally send the request with the 'send' method. The function to handle this should look something like this:
function requestUsingPOST() {
  createXMLHttpRequest();
  var url = "/cgi-bin/test1.dbw?timeStamp=" + new Date().getTime();
  var queryString = createQueryString();
  xmlHttp.onreadystatechange = handleStateChange;
  xmlHttp.open("POST", url, true);
  xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xmlHttp.send(queryString);
}
The URL above points to a dBase Plus web application called 'test1.dbw'. The URL here is a relative address, but absolute addressing is also possible. You also should note that we've appended a timestamp to the URL as a name-value pair. This isn't a necessity per se, but some browsers cache their pages and won't make a request from the server for a page it has already seen, unless the user uses the refresh button on that page. By appending a timestamp each request is considered to be a unique page that doesn't match any of the cached pages. This prevents the user from getting the same result as the first result when making a request through our Ajax web page.
The 'queryString' variable is the data we want to send to our dBase program. The data will be passed in the form of a string. The string may contain a set of name-value pairs or XML in string form, or just plain text. However, since dBase currently has an object optimized for parsing name-value pairs, it will be the suggested format of the query string. For now we will assume that the 'createQueryString' JavaScript function will create our string for us. This helps us remove the Ajax method from the implementation
Name-value pairs are the most common way to transmit data across the web via the browser. Name-value pairs are sent as a single string either appended to the end of a URL via the GET method or by itself via the POST method. The format of this string has been standardized. The standard is to list pairs one after the other in any order you choose. A pair is a name followed by its value separated by an equal sign (=). Name-value pairs are separated from each other with the ampersand symbol (&). If the string is sent via the GET method, it is separated from the URL using a question mark (?).
Sending a request via the GET method
We can also send our request via the GET method with Ajax. However, as stated before, the POST method is the preferred method from the perspective of this article. So, if you wish, it is completely possible to skip this section and go on to the next.
The GET method is very much like the POST method with only a few exceptions. Instead of sending your data in the body of the send method, we instead attach it to the end of the URL. Since there is nothing in the body of the request to encode we will not need to make a call to the 'setRequestHeader' method. When sending data via GET you are restricted to sending it as name-value pairs. Taking these exceptions into account would make our new function look something like this:
function requestUsingGET() {
  createXMLHttpRequest();
  var queryString = "/cgi-bin/test1.dbw?";
  queryString = queryString + createQueryString() + "&timeStamp=" + new Date().getTime();
  xmlHttp.onreadystatechange = handleStateChange;
  xmlHttp.open("GET", queryString, true);
  xmlHttp.send(null);
}
Note that the URL and the query string are now the same and the first parameter of the 'open' method has been changed to "GET". Also, the parameter of the 'send' method is now null.
Receiving a request in dBase
Nothing is complicated about getting data from the server with a dBase web application. This is particularly true if you send the data as name-value pairs. dBase Plus comes with a class, CGISession, that can open a connection to the server, abstract the data sent by the client, and place name-value pairs into its own associated array structure with just a few lines of code. The CGISession class will handle all this regardless of the method used to send the data from the client to the server. All you need to do is include the custom class file that defines it, make an instance of the object, and call its 'connect' method. The beginning of your application should include the following:
set procedure to WebClass.cc additive
oCGI = new CGISession()
oCGI.connect()
The CGISession object is inherited from the AssocArray class and abstracting the values sent to the server is like abstracting values from an AssocArray object. Let's assume the client web page sent the first and last name of the user as two name-value pairs, 'firstName' and 'lastName'. To assign the user's full name to a string you would insert a line such as this:
fullName = oCGI["firstName"] + " " + oCGI["lastName"]
Now that we have the client's request and the data they sent us it is just a matter of your program generating the response you desire. The next section will focus on how to take that response and send it back to the client.
Sending a response from dBase
Sending the data is quite possibly easier to send with Ajax than it is with normal dBase web applications. The reason is that when normally you would have to send an entire web page, you only need to send what is needed to update a part of an existing page. This can be XML code or just a line of plain text. For now let's just assume you want to send a single line of text. The only thing you need to do is send a header that tells the client how to read the response and then send the response itself. This is all done by using the 'puts' method of the 'fOut' property of the CGISession object. Assuming we have the full name of the client in a local variable called 'fullName' our response might look something like this:
responseText = "Hello " + fullName + "!"
oCGI.fOut.puts("Content-type: text/html")
oCGI.fOut.puts('')
oCGI.fOut.puts(responseText)
Once your response is complete you should assign null to the value of the CGISession instance to remove it.
Receiving the server's response
Switching back to the client-side, let's assume that we have already made our request to the server and we are now awaiting a response. We need a way for the current page to know when that response has arrived. This has already been handled in part by our assignment of the 'handleStateChange' function to the 'onreadystatechange' event. The 'handleStateChange' function should look something like this:
function handleStateChange() {
  if (xmlHttp.readyState == 4) {
    if (xmlHttp.status == 200) {
      parseResults();
    }
  }
}
Every time the state of the XMLHttpRequest object changes the above function is called. However, we don't want it to parse a server response every time it is called because not all state changes are valid responses from the server. Therefore, before we call the function to parse the results, we check to see that the 'readyState' property is equal to 4. This means that the server's response has been both received and loaded by the client. Then we check to see that the 'state' property is 200, which means that everything is "OK". If a server error occurred, then 'state' would be equal to something else. ('A file not found' error equals 404.)
Parsing the server's response
Once all is okay the 'parseResults' function gets called. Let us assume that we want the response sent by the server to be displayed as just text within a HTML 'div' tag within our web page. First we would give that HTML 'div' tag an ID property, such as 'serverResponse'. Once it has an ID it can then be identified by our JavaScript functions using the 'getElementById' method of the document object. Since our 'div' tag is only designed to hold the response of the server, it should contain either one text node or no nodes at all. To understand what I mean by nodes you may need to understand first a little bit of the DOM structure.
DOM stands for Document Object Model. It's a specified way of looking at the structure of a document. In the case of HTML, each tag or segment of text represents a node. Each node, with exception to the overall document, has a parent node. Parent nodes are the HTML tags that contain other tags or text. All parent nodes are expected to know who their children are, and vice versa. This puts the structure of a document into the form of a tree.
Since our 'div' tag could contain a former response in it, we may want to remove the current contents first. This is done through the 'removeChild' method of the parent node. The method requires a reference to the child you wish to remove, which can be found in the parent tag itself. The parent tag has an array property that contains a list of all its children. Assuming only one child at most, we want to remove the child in the zero index. We should also perform a check so that we don't try to remove a child that isn't there. The 'hasChildNodes' method can be used for this purpose. Next we want to take the servers response, which is held in the 'responseText' property of the XMLHttpRequest object, and make it into a text node using the 'createTextNode' method of the document object. Finally we want to append the text node to our HTML 'div' tag using its 'appendChild' method. This is what our function should look like:
function parseResults() {
  var responseDiv = document.getElementById("serverResponse");
  if (responseDiv.hasChildNodes()) {
    responseDiv.removeChild(responseDiv.childNodes[0]);
  }
  var responseText = document.createTextNode(xmlHttp.responseText);
  responseDiv.appendChild(responseText);
}
Now it is time to piece together what we have learned into a working example.
Example application
Our example will be a single web page with two input boxes and two push buttons. The user will be asked to enter in their first and last name. The user can then choose to send his/her name with either the POST or the GET method by pressing the push button that corresponds. Our example will have one dBase application that will take in the first name and last name of the user, and the method the user choose for data transfer, and build a single line of text as a response. The text is sent back to the client and the browser should insert that text directly into the current page. If the user executes this communication more than once, then the web page will remove the old response before inserting the new one.
We are going to need two files for this example. The first is our HTML document, 'test1.html', which the user will access directly. This file goes in the folder your server uses to hold public HTML documents. As an example, if you performed a typical install of the Apache Web Server on your computer, you would place this file into the 'htdocs' folder where Apache was installed. The other document is our dBase application, 'test1.prg', which goes where you normally run your dBase web applications. Going by the same example, if you performed a typical installation of the Apache Web Server, then you would place this file into the 'cgi-bin' folder where Apache was installed.
Below is the text of these two documents:
-test1.html-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title id="title">Sending Request Data Using GET and POST</title>
    <script type="text/javascript">
      var xmlHttp;
      function createXMLHttpRequest() {
        if (window.ActiveXObject) {
          xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        else if (window.XMLHttpRequest) {
          xmlHttp = new XMLHttpRequest();
        }
      }
      function requestUsingPOST() {
        createXMLHttpRequest();
        var url = "/cgi-bin/test1.dbw?timeStamp=" + new Date().getTime();
        var queryString = createQueryString() + "&method=POST";
        xmlHttp.onreadystatechange = handleStateChange;
        xmlHttp.open("POST", url, true);
        xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xmlHttp.send(queryString);
      }
      function requestUsingGET() {
        createXMLHttpRequest();
        var queryString = "/cgi-bin/test1.dbw?";
        queryString = queryString + createQueryString() + "&method=GET&timeStamp=" + new Date().getTime();
        xmlHttp.onreadystatechange = handleStateChange;
        xmlHttp.open("GET", queryString, true);
        xmlHttp.send(null);
      }
      function createQueryString() {
        var firstName = document.getElementById("firstName").value;
        var lastName = document.getElementById("lastName").value;
        var queryString = "firstName=" + firstName + "&lastName=" + lastName;
        return queryString;
      }
      function handleStateChange() {
        if (xmlHttp.readyState == 4) {
          if (xmlHttp.status == 200) {
            parseResults();
          }
        }
      }
      function parseResults() {
        var responseDiv = document.getElementById("serverResponse");
        if (responseDiv.hasChildNodes()) {
          responseDiv.removeChild(responseDiv.childNodes[0]);
        }
        var responseText = document.createTextNode(xmlHttp.responseText);
        responseDiv.appendChild(responseText);
      }
    </script>
  </head>
  <body>
    <h1>Enter your first and last name:</h1>
    <table>
      <tr>
        <td>First name:</td>
        <td><input type="text" id="firstName" />
      </tr>
      <tr>
        <td>Last name:</td>
        <td><input type="text" id="lastName" />
      </tr>
    </table>
    <form action="#">
      <input type="button" value="Send parameters using POST" onclick="requestUsingPOST();" /><br />
      <input type="button" value="Send parameters using GET" onclick="requestUsingGET();" />
    </form>
    <h2>Server Response:</h2>
    <div id="serverResponse"></div>
  </body>
</html>
-test1.prg-
try
  set procedure to WebClass.cc additive
  oCGI = new CGISession( )
  oCGI.connect( )
  if empty(oCGI["firstName"])
    if empty(oCGI["lastName"])
      responseText = oCGI["method"] + ": First or last name required!"
    else
      responseText = oCGI["method"] + ": Hello Sir/Madam " + oCGI["lastName"]
    endif
  else
    if empty(oCGI["lastName"])
      responseText = oCGI["method"] + ": Hello " + oCGI["firstName"]
    else
      responseText = oCGI["method"] + ": Hello " + oCGI["firstName"] + " " + oCGI["lastName"]
    endif
  endif
  oCGI.fOut.puts("Content-type: text/html")
  oCGI.fOut.puts('')
  oCGI.fOut.puts(responseText)
catch (exception e)
  oCGI.fOut.puts("Content-type: text/html")
  oCGI.fOut.puts('')
  oCGI.fOut.puts("Error!")
endtry
oCGI = null
quit
The 'requestUsingPOST' and 'requestUsingGET' functions have been modified for this example. They now append a name-value pair to the query string so that the method used to send the data could be identified. This is only useful for this example where we want to test both methods. Normally you would only use one or the other. The execution of our Ajax code occurs when the input buttons receive an 'onClick' event. This is similar to the onClick events for dBase push buttons. When the user presses either button, the execution we outlined above occurs. In our dBase web application we have enclosed the entire application in a try and catch block. This should be done with all your applications as it is easy to encounter errors in web-based programs.
Before we can run the application, we still need to build it. When building your web application you should add the key word 'web' to the end of your build statement. This isn't a necessity, but it will strip your application of unnecessary functionality, such as forms and local output, which isn't needed for an application that is accessed remotely through a web browser. It is also better to build your web application as a dbw file rather then an exe. There are some instances where executing an exe file through your web server will create problems or simply not work.
Appendix A
Here is the list of methods and properties for the XMLHttpRequest object:
Property Description
onreadystatechange An event handler for an event that fires at every state change.
readyState Returns the state of the object as follows:
0 = uninitialized, 1 = open, 2 = sent, 3 = receiving and 4 = loaded.
responseText Returns the response as a string.
responseXML Returns the response as XML. This property returns an XML document object, which can be examined and parsed using W3C DOM node tree methods and properties.
status Returns the status as a number (e.g. 404 for "Not Found" and 200 for "OK").
statusText Returns the status as a string (e.g. "Not Found" or "OK").
Method Description
abort() Aborts the current request.
getAllResponseHeaders() Returns the complete set of HTTP headers as a string.
getResponseHeader( headerName ) Returns the value of the specified HTTP header.
open( method, URL [, async [, userName [, password]]] ) Specifies the method, URL, and other optional attributes of a request.
The method parameter can have a value of "GET", "POST", or "PUT" ("GET" is used when requesting data and use "POST" when sending data, especially if the length of the data is greater than 512 bytes).
The URL parameter may be either a relative or complete URL.
The "async" parameter specifies whether the request should be handled asynchronously or not – "true" means that script processing carries on after the send() method, without waiting for a response, and "false" means that the script waits for a response before continuing script processing.
send( content ) Sends the request.
setRequestHeader( label, value ) Adds a label/value pair to the HTTP header to be sent.