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.
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"); });
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>
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.
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>
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.
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.
Dive deep into our treasure trove of embedded web server and IoT tutorials designed for enthusiasts like you. Yet, if deadlines loom or challenges arise, remember our experts are on standby. With Real Time Logic, you have the freedom to learn and the assurance of expert support when you need it. Let's bring your project to fruition your way.
Expedite your IoT and edge computing development with the "Barracuda App Server Network Library", a compact client/server multi-protocol stack and toolkit with an efficient integrated scripting engine. Includes Industrial Protocols, MQTT client, SMQ broker, WebSocket client & server, REST, AJAX, XML, and more. The Barracuda App Server is a programmable, secure, and intelligent IoT toolkit that fits a wide range of hardware options.
SharkSSL is the smallest, fastest, and best performing embedded TLS stack with optimized ciphers made by Real Time Logic. SharkSSL includes many secure IoT protocols.
SMQ lets developers quickly and inexpensively deliver world-class management functionality for their products. SMQ is an enterprise ready IoT protocol that enables easier control and management of products on a massive scale.
SharkMQTT is a super small secure MQTT client with integrated TLS stack. SharkMQTT easily fits in tiny microcontrollers.
An easy to use OPC UA stack that enables bridging of OPC-UA enabled industrial products with cloud services, IT, and HTML5 user interfaces.
Use our user programmable Edge-Controller as a tool to accelerate development of the next generation industrial edge products and to facilitate rapid IoT and IIoT development.
Learn how to use the Barracuda App Server as your On-Premises IoT Foundation.
The compact Web Server C library is included in the Barracuda App Server protocol suite but can also be used standalone.
The tiny Minnow Server enables modern web server user interfaces to be used as the graphical front end for tiny microcontrollers. Make sure to check out the reference design and the Minnow Server design guide.
Why use FTP when you can use your device as a secure network drive.
PikeHTTP is a compact and secure HTTP client C library that greatly simplifies the design of HTTP/REST style apps in C or C++.
The embedded WebSocket C library lets developers design tiny and secure IoT applications based on the WebSocket protocol.
Send alarms and other notifications from any microcontroller powered product.
The RayCrypto engine is an extremely small and fast embedded crypto library designed specifically for embedded resource-constrained devices.
Real Time Logic's SharkTrust™ service is an automatic Public Key Infrastructure (PKI) solution for products containing an Embedded Web Server.
The Modbus client enables bridging of Modbus enabled industrial products with modern IoT devices and HTML5 powered HMIs.