AJAX Isn't Just for Cleaning Dishes Anymore

Web Languages
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Until recently, moving to browser-based RPG IV applications has been limited because Web pages have to be reloaded or new pages need to be displayed in order to give the end-user the appropriate feedback. Users never really had the same quality experience as they had with a 5250 green-screen applications.

For example, if you provide users with a file maintenance application in 5250, they may get a prompt that says "Type the Customer Number, then press Enter." When they type in an invalid customer number, a message such as "Customer 5678 not found" is displayed, and the cursor is positioned in the customer number input field. Normally, the field would also be set to reverse-image or highlighted in some way. When users type in a valid customer number, the data is displayed and can be updated as necessary. When the users finish making the changes, they press Enter and get immediate feedback. For example: "Address line 1 cannot be blank" or "Customer changes successful."

With a typical Web- or browser-based application, the user types in a customer number on a Web page, which calls an RPG IV program to check if that customer exists. If the customer is not found, another Web page is created with the message "Customer 5689 not found." It is displayed in that same browser window along with the infamous "Press the Back button in your browser to fix this error" message. Tragic.

If the user types in a good customer number, a new Web page is displayed showing the customer's data. The user makes any changes and then presses the Submit button. Some JavaScript may be used on that page to edit-check the input fields before passing the data along to another RPGIV program that performs the final validation and records the changes. If there is another error, the user once again sees "Press the Back button in your browser to fix this error."

While this does provide the end-users with a conventional browser interface, it is not a fun experience.

I believe this common type of experience is one of the reasons a lot of people are staying away from the browser as a user interface. They see it as being better-looking but not a better end-user experience. This is not good for RPG IV programmers because, unless RPG IV programmers start moving nearly all apps to some form of GUI, there will be little future for the iSeries box and thus few employment opportunities for RPG programmers. See my related article on this topic in this week's issue.

Asynchronous JavaScript and XML

An emerging technology that is becoming the "next big thing" in application development isn't a new product or a new language (thank goodness!). Instead, it is a collection and organization of a couple of existing technologies that you already have. (Read: You don't have to buy anything new to make them work.) That technology is known as Asynchronous JavaScript and XML, or simply AJAX.

Two important facts about AJAX are 1) you don't have to buy anything to make it work, and 2) it allows you to create browser-based applications that behave very similarly to 5250-based applications, but with a graphical user experience. That is, you create applications that use one page rather than several different pages to give your end-users a much more refined experience.

A side effect is that you avoid all those page refreshes and pop-up windows. And you don't need to have multiple browser windows open for an application. Everything is done in one page, or two or three, similar to 5250 display file-based applications.

Let's break down AJAX and look at what it is.

AJAX uses asynchronous JavaScript to communicate with your server without requiring the current page to send data to a server via a Submit button. The JavaScript in the existing page posts a request to your RPG IV program, and it waits for a response in the background while it releases the browser back to the user. The user never knows what's going on in the background (unless you want him to).

In other words, it effectively uses the idle time in the browser to send the customer number (from our previous example) up to the server and get feedback as to whether or not it was a good customer number. When the JavaScript receives the response, it can do whatever it wants, including writing HTML or text to the existing page. That way, the server doesn't need to respond with a new Web page or a CGI request that outputs an entirely new page; instead, it returns information to the current browser page. That data is used to update the current page.

For example, a message that says "Customer not found. Try again" could be displayed, and the cursor could be automatically positioned in the customer number input field. I also like to change the background color of the input field when it is causing an error.

The key to all of this is through the use of the JavaScript XMLHttpRequest object. To use this object, you simply declare an instance of it. It does depend on which browser you're using. There are several methods to create this object correctly; the one I use most is shown below. However, any method you prefer will probably be OK.

The following illustrates the GoAjax() function I wrote to generically evoke an AJAX request in an HTML page.



  var req;

function GoAjax(myUrl) {

   if (window.XMLHttpRequest) {  // FireFox, Safari,...
        req = new XMLHttpRequest();
        if (req.overrideMimeType) {
            req.overrideMimeType('text/xml');
        }
    } else if (window.ActiveXObject) { // Microsoft IE
        try {
              req = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
          try {
             req = new ActiveXObject("Microsoft.XMLHTTP");
          } catch (e) {}
        }
    }

    if (!req) {
        alert('Darn it! No XMLHTTP request.');
        return false;
    }
                
    req.onreadystatechange = myCallback;
    req.open('GET', myUrl, true);
    req.send(null);
}

This JavaScript code creates an HTTP Request object and then uses the GET method to open a dialog with the Web server at the designated URL. The HTTP Request is first attempted the Mozilla way (NetScape/FireFox/Safari) using the XMLHttpRequest object. If that fails, the code attempts to create the object using Microsoft's ActiveXObject. Of course, it wouldn't be Microsoft if there weren't two versions of its stuff in production. The good news is that the resulting object is the same, regardless of Mozilla or Microsoft methods. Once it is created, you can use it the same way throughout the rest of the process.

In order to allow the end-user to continue to use the browser while the request is sent off to the iSeries, we need to do two simple things: 1) We need to tell the created object the name of a function to call when the request receives a reply from the server, and 2) we need to send the request with the async attribute set on.

To indicate the name of the function to call when the server responds, the onreadystatechange property of the XMLHttpRequest object is used. This field holds the so-called "callback procedure." It gets its name from the fact that you're telling the process to "call back" when it is finished. What gets called back is the function whose name you provide.

This is performed in a three-step process. The following JavaScript code in our GoAjax() function accomplishes these three steps:

    req.onreadystatechange = myCallback;
    req.open('GET', myUrl, true);
    req.send(null);

Step 1: Assigning a Callback Function

In JavaScript, you assign a callback by assigning the name to the onreadystatechange property of the XMLHttpRequest object, as follows:

    req.onreadystatechange = myCallback;

In this example, myCallback is the name of the callback function. This function is called when the server responds to the AJAX request.

A typical callback routine will check the state of the response and react accordingly. There are five possible states (known as the "ready states" ) for a response:

  • 0 = uninitialized
  • 1 = loading
  • 2 = loaded
  • 3 = interactive
  • 4 = complete

Effectively, the only ready state you care about is 4. This tells you that the request has completed and you may begin to extract the data sent to you by the server. Here's a simplified JavaScript callback function that tests the ready state of the request:

 function  myCallback() {
    if (req.readyState == 4) {
       if (req.status == 200) {
          myResponseFunc(req.responseXML);
        }
    }
 }

In this example, the ready state is checked. If it is equal to 4, then it checks the status of the response. If status 200 comes back, the requested URL passed to the server on the req.open() function was successful. At this point, we know everything should be OK, and we can call a user-written function to handle the data that the server sends to the browser.

Step 2: Open a Connection to the Server

To cause the asynchronous request to be issued, you have to pass the CGI "method" the URL-encoded string and indicate that you want an asynchronous request. The following line of JavaScript does this for us.

    req.open('GET', myUrl, true);

The first parameter of the req.open function is 'GET', which indicates that we want to use the CGI GET method to send the request to the server. This is the same GET method as the GET method used on HTML forms. The other options are POST and HEAD, which also send the requests to the server but cause different results. The HEAD method simply requests that only the HTTP headers be returned. Typically, you don't care about the HEAD method. The POST method causes the data to be sent through a channel that is hidden from snoopers; it is not stored in the browser's history file.

The second parameter of the req.open function is the URL you want to send to the server. This URL should be encoded/escaped before it is sent. Normally, you can encode URLs using the escape() function, but newer versions of JavaScript support encodeURL() and encodeURLComponent(). I use the following JavaScript function to check for which version (escape or encodeURIComponent) is installed and call it accordingly.

function encodeMe(value)
{
   if (encodeURIComponent) {
     return encodeURIComponent(value);
   }
   if (escape) {
       return escape(value);
   }
   return value;
}

In my JavaScript, I would normally do something like this to encode a value being added to a URL string:

   var theText  = document.CUSTMAIN.CSTNAME.value;
   var url = "/cgi-bin/myCGIPGM?CSTNAME=" + encodeMe(theText);

The third parameter of the open function indicates whether you want synchronous or asynchronous processing. If it's unspecified or if "false" is specified, synchronous processing is performed. If "true" is specified, asynchronous processing is performed.

Synchronous requests can be useful, but not for what we're trying to accomplish, so make sure you specify "true" for this parameter; otherwise, you'll end up with unhappy users waiting while the server is working—not a nice thing to do to someone. Besides, it's called AJAX, not SJAX.

Step 3: Send the Asynchronous Request

If you need to send more information to the server's CGI program, you may do so using the send() function of the XMLHttpRequest object. Otherwise, you need to indicate that nothing else is being sent and that it's OK to start performing your request. So you need to send nothing. Do this by passing "null" as the parameter for the send() function, as follows:

    req.send(null);

Now the request is sent, and if everything was done correctly, your RPG IV CGI program has been called and can start building the response.

Your RPG IV program responds either by sending nicely formatted XML data or by sending plain text. Either way, the JavaScript in your HTML page will need to extract or parse this data and then update the Web page.

Parsing the response and updating the Web page are topics for the next article on this important topic.

Now a Little Bad News

Unfortunately, some users are blocking scripts in their browsers. We IT staffers often use this as a reason to avoid JavaScript or VBScript in our HTML pages. I blame this on associative post-dramatic stress syndrome (not sure if that's a real term or one that I just made up). But it seems to me that if we have a problem on a PC due to some random security hole potentially caused by ActiveX controls or VBScripting in Internet Explorer, we fight it by blocking all scripting in all languages in everyone's browser. Sort of like killing all the chickens in Arkansas because a few chickens in Asia had the flu. In other words, it's overkill.

The good news is the current release of some of the browsers and the next release of many others offer selective Script blocking. This allows you to block Web sites from running scripts just like you now block email domains with your junk email filters. So you can allow scripts to run on the good Web sites, like mcpressonline.com or rpgiv.com, and block them on the not-so-good sites. This means that scripting, in particular JavaScript, can be supported and relied on in your day-to-day browser-based applications.

Google, arguably the biggest single advocate of JavaScript and AJAX use in the world today, uses JavaScript everywhere. In fact, I've already done consulting/contracting with two customers who wanted to add a "Google Suggest" style of interface to a browser-based application. I must admit, once we got the HTML looking the way they wanted it, it produced some very impressive results, especially considering it was iSeries and RPG IV behind it all.

Now that we have a GUI alternative to DDS that everyone already owns, RPG programming is starting to be cool again! Get on board and have fun!

This is the first in a series of articles on AJAX programming with iSeries, so stayed tuned. And watch for my new book about AJAX with iSeries, coming soon from MC Press.

Bob Cozzi is a programmer/consultant, writer/author, and software developer of the RPG xTools, a popular add-on subprocedure library for RPG IV. His book The Modern RPG Language has been the most widely used RPG programming book for nearly two decades. He, along with others, speaks at and runs the highly-popular RPG World conference for RPG programmers.

BLOG COMMENTS POWERED BY DISQUS