Ajax for Beginners

You may want to read the article we had published in the RTC magazine December 2011 if you are new to AJAX. The article discusses some benefits of using AJAX and JSON in modern web applications. See the App Servers and Lua Scripting Speed Rich Web Applications for Small Devices article for more information.

The traditional way of generating dynamic web pages is to generate everything on the server by, for example, using a server side scripting language such as LSP. For example, in the HTML form tutorial, we showed you how to dynamically generate a basic login page by using LSP on the server side.

Over the years, it has become increasingly popular to combine server side generated content with client side generated content. More and more web applications rely on using Javascript as a method for dynamically changing the user interface on the fly. The bulk of the user interface is still typically generated by the server including the JavaScript code. When the browser has loaded a server generated HTML page, the embedded JavaScript code inside the HTML response data is executed by the browser. This Javascript code can, for example, connect back to the server and fetch data in real time, which is then instantly updated in the client without having to refresh the page.

browser-server-com

Figure 1: JavaScript code in the dynamically created HTML page uses Ajax when connecting back to the server.

Ajax is an acronym and means Asynchronous Javascript and XMLHTTPRequest. The XMLHTTPRequest object, which is accessible from JavaScript, is a browser API/object that enables JavaScript code to send HTTP commands directly to a server. Asynchronous means that the functions in the XMLHTTPRequest object do not block. Instead a JavaScript callback function is provided which is then called by the XMLHTTPRequest object when the server returns a response. Using callbacks (aka events) is common in JavaScript since the typical browser JavaScript environment is single threaded. A blocking call would cause the browser user interface to freeze while waiting.

The XMLHTTPRequest API is weird and cumbersome, but luckily many JavaScript libraries make it very easy to use this object. We will be using the very popular jQuery JavaScript library instead of directly using the XMLHTTPRequest. Although you can find many libraries that help you fast track your client side JavaScript development, we particularly like jQuery since it is small and makes it easy to write compact JavaScript code without having to learn the details of the browser's Document Object Model. JQuery is your perfect companion when it comes to writing your client side JavaScript code. The JQuery JavaScript library is also included in the Mako Server's resource ZIP file mako.zip. You can load this library from the Mako Server by navigating to http://localhost/rtl/jquery.js.

Although providing a comprehensive tutorial on JQuery is beyond the scope of this article, we will give you a quick introduction to the $() function since many get very confused by this JQuery library function. In JavaScript, $ is a valid character for variable names. The JQuery $() function is a Jack of all trades in JQuery and the function accepts a wide variety of arguments. For example, the following code will cause the browser to popup a "hello" message when the page has loaded.

$(function() {
   alert("hello");
});

Example 1: passing in an anonymous function to the JQuery $() function.

Let's go ahead and create a basic JQuery example that installs a keyboard event handler. Every time the event triggers, the keyboard key number is converted to text and the text is then appended to the HTML in the browser.

00: <html>
01: <head>
02: <script src="/rtl/jQuery.js"></script>
03: <script>
04: $(function() {
05:    $("#out").empty();
06:    $("#in").keypress(function(ev) {
07:       $("#out").append(String.fromCharCode(ev.which));
08:    });
09: });
10: </script>
11: </head>
12: 
13: <body>
14: <h1 id="out">Please enable JavaScript</h1>
15: <input id="in" type="text" />
16: </body>
17: </html>

Example 2: dynamically changes the HTML from data in keyboard events

We install an “on page load” event callback function on line 4 by providing an anonymous function to the jQuery $() function. The “on page load” callback function will be called when the page has loaded and the DOM is ready. We start modifying the DOM on line 5 so it is important that the DOM is ready at that point.

Line 13 to 16 is our static HTML. The message " Please enable JavaScript" should not be visible to users that have JavaScript enabled since the JavaScript code on line 5 erases the content within the <h1> element. The code construction $("#out").empty(); means look up the HTML element in the DOM tree whose ID is "out" and empty this object.

The construction on line 6 means look up the HTML element in the DOM tree whose ID is "in" and install a keyboard event handler within the realm of the <input id="in" type="text" /> element. When a key is pressed in this input element, the keyboard event triggers, which in turn looks up the "out" element, converts the keyboard event to a character, and appends the character to the “out” element. The “out” element is the H1 tag on line 14.

You can run example 2 as follows:

  1. Download and install the Mako Server
  2. Create a directory such as "test"
  3. Start the Mako Server as follows: mako -l::test
  4. Download  example 2  
  5. Save the example in your "test" directory
  6. Use a browser and navigate to http://localhost/jquery.html, where localhost is the name of the computer running your Mako Server.

Adding Ajax to the example

As you have probably noticed, we have so far not used any Ajax. We will soon add Ajax to our example. It is not possible to use Ajax if you do not have an understanding of how to manipulate the browser's DOM since you cannot display the result from your Ajax response unless you know how to update the HTML by using JavaScript. Example 2 shows how to do that.

We use the JavaScript function String.fromCharCode() in example 2 on line 7 above. This function converts the key code from the keyboard event to a string containing one character. Let’s go ahead and modify this code to the following:

   $("#in").keypress(function(ev) {
      $.getJSON(window.location,{key:ev.which}, function(rsp) {
         $("#out").append(rsp.char);
      });

jQuery provides a number of functions that simplifies the use of the browser’s raw XMLHTTPRequest API. One of these functions is $.getJSON(), which sends URL encoded data to the server and expects JSON as the response data from the server. The first argument to this function is window.location which is the URL to the page itself. This means we will be sending the Ajax request back to the same LSP page on the server. The second argument is a JavaScript object containing the key-value pairs we want to send to the server. A JavaScript object is similar to a table in Lua. We only need one key/value pair in this example and that is the keyboard event number. This number will be converted to a string containing one character by Lua code on the server side and the response will be encoded as JSON. The last argument to $.getJSON is the “on server response” callback function. The ‘rsp’ argument is the decoded JSON response data from the server. The JavaScript object ‘rsp’ (from the decoded JSON) contains one property “char” which is the keyboard event number converted to a string by the server side Lua code.

The complete modification to example 2 is shown below. Code in green is the modified JavaScript code and code in blue is the new server side code that takes care of Ajax requests sent from the client.

01: <?lsp
02: if request:header"x-requested-with" then
03:    local key=request:data"key"
04:    if key then
05:       local resp
06:       key=tonumber(key)
07:       if key and key >=32 and key <= 127 then
08:          resp=string.char(key)
09:       else
10:          resp = key and string.format(' "%d" ',key) or '?'
11:       end
12:       trace(resp)
13:       response:json({char=resp})
14:    end
15: end
16: ?>
17: <html>
18: <head>
19: <script src="/rtl/jquery.js"></script>
20: <script>
21: $(function() {
22:    $("#out").empty();
23:    $("#in").keypress(function(ev) {
24:       $.getJSON(window.location,{key:ev.which}, function(rsp) {
25:          $("#out").append(rsp.char);
26:       });
27:    });
28: });
29: </script>
30: </head>
31: <body>
32: <h1 id="out">hello</h1>
33: <input id="in" type="text" />
34: </body>
35: </html>

Example 3: the complete Ajax example

Line two in the above example is strictly not needed in our example. It’s just an extra security measure that makes sure only Ajax requests can trigger the Lua code on line 3 to 14. jQuery adds the HTTP header “x-requested-with” and checking for this header is a convenient method for filtering out all requests that are not Ajax requests.

We check if our client side Ajax code (line 24) sent the server the key/value pair “char” on line 4. It would be a program error if this was not set. Line 5 to 13 deals with the Ajax request and the JSON response. The keyboard event is converted to a string character on line 8 if it is within the range of the standard printable ASCII table. Line 10 triggers if the keyboard key is a non printable character. The code on this line converts the number to a string number. Non printable characters are generated from keyboard events such as the keyboard “Enter” button, which generates the key number 13.

Line 12 is for debugging purposes. The response string is printed to the server’s trace buffer. You will see this being printed if the server is running in a console i.e. not running as a background service.

Line 13 is where the magic happens. The method response:json takes a Lua table as argument, converts this to JSON, sends the JSON data to the client, and stops the script (the LSP page) – in other words, no code is executed on the server after line 13. Lua functions do not require parentheses if only one argument is supplied to the function. Line 13 can be changed to response:json{char=resp}. We dynamically create a Lua table and pass this table into method response:json(). This table includes one key/value pair, where ‘char’ is the key and the data in ‘resp’ is the value.

Note that the server side LSP page returns the HTML starting on line 17 and ending on line 35 if the request is not Ajax and if the client did not send the “char” key/value pair. If you think about this for a second, you will realize that the LSP code in example 3 can send both HTML and JSON responses to a client, where the HTML is the complete page.

Download example 3 and save the example in your “test” directory. Use a browser and navigate to http://localhost/ajax.lsp. Enter some data into the input field and watch the data being printed to the server's console and added to the HTML page in the browser.

Download example 3

Ajax Limitations

Ajax is great in solutions where the client is the one responsible for generating all the events, but how do you use Ajax if the server is the one generating events? The server has no way of telling the client since a HTTP request is only open when a client sends a request to the server. One way to solve this problem is to use Ajax and constantly poll the server for new data. This is not an ideal solution since you get a delay in the event notification on the client due to the poll delay. You also create unnecessary network traffic, and the server side code must be designed such that it can buffer the event data until the client sends the poll request.

You may have heard of WebSocket and that it is a web technology providing full-duplex communication channels over a single TCP connection. Using WebSocket would fix the polling problem since the client and server maintain a persistent connection where the server can, at any time, send an event to the client. Check out our online WebSocket tutorial if you want to learn more about WebSockets and how to send asynchronous bi-directional events between a client and a server.

Posted in Tutorials by bd