Easy Ajax with jQuery

Example 2 – Chat with jQuery

To demonstrate the true power of jQuery, we’re going to make a fully featured Ajax chat application. This will allow users to post messages, and automatically update itself — all without any page refreshes. As we’re now dealing with a slightly more complex application, I’ll also take you deeper into jQuery, demonstrating other handy functions.

First, we’ll plan out the application. We won’t need much for this app — a front end, a back end, and the jQuery library. However, there will be a fair bit of code for both the back and front ends of the app, so our basic plan will let you know what to expect from the system.

Planning the Server Side

The back end of our application needs to process message submissions and output the messages. With this in mind, let’s put together a rough outline of the back-end code:

  • connect to database
  • if a message was submitted
  • insert message into database
  • delete old messages
  • fetch messages from the database and display as XML

As you can see, it’s all very simple and straightforward. You can use this plan as a guide if you have to write a back end in another language.

Planning the Client Side

The front end has to call the back end using Ajax, similarly to the approach we used in the first example. It has to handle the submission of the message-posting form, and update the chat window with newly submitted messages at regular intervals. However, we’re going to add another feature here — we’ll use the current UNIX timestamp to determine which messages have already been downloaded, and only fetch the new messages, reducing bandwidth usage and server load. Here’s a rough outline of the front-end code:

  • on page load
  • set current timestamp to 0 (all messages will be posted after this, i.e. all messages will be fetched)
  • call function to fetch new messages
  • function: fetch new messages
  • send request to server using POST
  • call function to parse XML response
  • add a timer to call this function after a second (increase frequency if server load is too high)
  • function: parse XML of new messages
  • set current timestamp as specified in the XML
  • if status code returned is ‘2’, no new messages, so end the function call
  • else, for each message in the response, add this to the top of the message window in this format:
  • author: message
  • on form submit:
  • send request to server using POST, specifying:
  • author name (user-specified)
  • message text (user-specified)
  • action noting that this is a post request
  • timestamp of the last request to the server
  • empty content of the message input box so that the user can start typing another message
  • call function to parse XML response (so that message posted is visible immediately)

This plan may seem far more complex than the back end, but thanks to jQuery, the code involved is fairly short.

Planning the Database

We’ll use a MySQL database to store the messages (although any SQL database will work, with a few tweaks to the code). We need a table with four columns: a column for the id of each message, two text columns to store the author of the message and the message itself, and a numerical timestamp column for our UNIX timestamps. Here’s the query that creates the table:

CREATE TABLE `messages` (  `id` int(7) NOT NULL auto_increment,  `user` varchar(255) NOT NULL,  `msg` text NOT NULL,  `time` int(9) NOT NULL,  PRIMARY KEY  (`id`) );

Because we can’t tell what length the message will be, we’ll use a text field for now.

Server-side Code (XML)

In building the back end, let’s first decide what the back end should output (to determine the interface between the back end and front end), and work backwards from there. Here’s a simple XML structure:

<?xml version="1.0"?> <response>  <status>1</status>  <time>1170323512</time>  <message>    <author>John Citizen</author>    <text>Hello world!</text>  </message>  <message>    <author>John Citizen</author>    <text>Hello world again!</text>  </message> </response>

Notice that I’ve added the tag 'status', with the value of '1'. As I mentioned above, a status code of 1 will represent a successful request with new messages, 2 as successful without new messages. Each instance of the message tag includes the author and his or her message.

Server-side Code (PHP)

Now, to the back end. I’ll have to do this in PHP, but because the output is XML you can write the back end in any language — Perl, ASP, whatever you like. Let’s start it logically by defining some configuration values so that we can easily change them later. We need database connection details, the number of messages we want to store in the database (databases can handle thousands of rows, so this figure can be set fairly high), and the number of messages to display when the user enters the chat. Here’s the code:

$dbhost = "localhost"; $dbuser = "root"; $dbpass = ""; $dbname = "chat"; $store_num = 10; $display_num = 10;

Now we need to get on to the basics of the back end itself. A database connection is required, but we also need to make sure that Internet Explorer doesn’t cache the request, and that the output is treated as XML. To make sure we’re able to identify any errors in the code, we’ll set error reporting to “all errors”. And to easily work with the request data, we’ll set a variable for every parameter in the request; each variable will take as its value the value of the request parameter. These few lines do the trick:

error_reporting(E_ALL); header("Content-type: text/xml"); header("Cache-Control: no-cache"); $dbconn = mysql_connect($dbhost,$dbuser,$dbpass); mysql_select_db($dbname,$dbconn); foreach($_POST as $key => $value)  $$key = mysql_real_escape_string($value, $dbconn);

The foreach line looks through all the POST data, and creates a variable for every parameter and assigns it a corresponding value (e.g. path/to/file.php?variable=value would set $variable to "value"). This simplifies the process of grabbing request data, as we don’t have to specify it manually.

Next we get to the main functionality. It’s at this point that we handle the insertion of messages into the database, and the retrieval of the latest few messages based on the number of messages to be displayed, as defined in $display_num. I mentioned when we planned the front end that we would specify an action stating that a message was being submitted. We now need to check for this action — let’s assign the parameter 'action' a value of 'postmsg' to specify that we’re performing this check and insert the data as a new row in the database; we’ll insert the current UNIX timestamp in the database while we’re at it.

However, we also need to clean out the database. Depending on your database space limits, you may want to restrict the number of posts stored. Generally, logging of messages is frowned upon, so I’ve decided to store ten messages by default. We’ll use a function to grab the id of the last inserted row, and determine the rows to delete based on the value of that id. For example, if we insert the eleventh message, we’ll subtract the number of stored messages (10) from the id of the latest one (11) which gives us the id threshold (in this case, 1). We can then delete all messages that have an id equal to or less than that threshold, which in this example would result in us deleting the first message. And, thanks to SQL, we can do this all in one query.

Here’s the snippet that checks for the 'postmsg' action, inserts the message into the database, and cleans it out on the fly as well:

if(@$action == "postmsg") {  mysql_query("INSERT INTO messages (`user`,`msg`,`time`)        VALUES ('$name','$message',".time().")");  mysql_query("DELETE FROM messages WHERE id <= ".        (mysql_insert_id($dbconn)-$store_num),$dbconn); }

Developers using other server side technologies should be able to write equivalent code easily enough. Notice that we call the time function to grab the current UNIX timestamp. We can safely assume that the value that time returns will probably not change during script execution (even on a slow server, this script executes in under one hundredth of a second). So when we return a timestamp to the front end later, we can just call the time function again and the value should still be reliable.

The code that’s left handles the job of fetching the latest messages from the database and outputting them as XML. This is where the XML I outlined above comes into play. However, the bulk of the code lies in the MySQL query. We utilize the power of SQL to handle most of the processing tasks, so that script execution time isn’t affected. Here are the requirements for our SQL query:

  • It should fetch only the author and text of each message.
  • It should only fetch messages that have not been downloaded before — the client has a timestamp of the latest request, so this timestamp can be inserted into the SQL query.
  • It should order the messages so that the latest comes last, allowing them to be output in reverse order.
  • It should limit the number of messages fetched to the number defined in the configuration.

Anyone who’s familiar with SQL will agree that this is all fairly simple stuff. For the rest of us, here’s the code that does the trick. First, the query:

$messages = mysql_query("SELECT user,msg             FROM messages             WHERE time>$time             ORDER BY id ASC             LIMIT $display_num",$dbconn);

The rest of the code is elementary. If no results are returned, set the status code to 0; otherwise, set it to 1. Output the initial XML, the XML for each message, and the final XML. That’s all! Here’s the code:

if(mysql_num_rows($messages) == 0) $status_code = 2; else $status_code = 1;   echo "<?xml version="1.0"?>n"; echo "<response>n"; echo "t<status>$status_code</status>n"; echo "t<time>".time()."</time>n"; while($message = mysql_fetch_array($messages)) {  echo "t<message>n";  echo "tt<author>$message[user]</author>n";  echo "tt<text>$message[msg]</text>n";  echo "t</message>n"; } echo "</response>";

The final code is all in the attached zip file, so don’t worry about copying this into your text editor. Now that the back end is finished, we can move on to the fun work — the HTML and jQuery!

Client-side Code (HTML)

Before we head into the jQuery, we need to prototype the HTML of the page. This way, when we have to work out which elements we are selecting to fetch or update using jQuery, we know what to do. We won’t need much: a wrapper div, a paragraph for the messages, and a form with fields for the user’s name and message, along with a Submit button. A briefly displayed loading message would add a final touch — we can remove this at the appropriate time using jQuery. Here’s the HTML:

<div id="wrapper"> <p id="messagewindow"><span id="loading">Loading...</span></p> <form id="chatform"> Name: <input type="text" id="author" /> Message: <input type="text" id="msg" /> <input type="submit" value="ok" /><br /> </form> </div>
Go to page: 1 | 2 | 3

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.