Xajax 0.5: Tips and Tricks: OnKeyUp Request Buffering
Xajax 0.5: Tips and Tricks: OnKeyUp Request Buffering
Notes: This code has 1 error I will try and fix later. If you use this function more then once the buffer doesn't get cleared. I will update later to include buffer clearing code.
We've had a few requests for information about this topic in the forum, so I thought I'd post some help here. There are often times when you want to fire off a xajax request to perform some server-side operation as the user types in an input text field. Perhaps the most common use is to create a search-as-you-type module similar to Google Suggest.
For the sake of this article, let's do something a little more simple. Let's create a simple application that, as you type into an input box, will tell you whether the string has an odd or even number of characters.
So first we create a xajax PHP function that will take a text string and modify the contents of a div element to show either the word "Even" or the word "Odd" depending on the text input:
function isOddOrEven($strText) { $objResponse = new xajaxResponse(); $objResponse->assign("textInfo", "innerHTML", (strlen($strText)%2==0?"Even":"Odd")); return $objResponse; } $xajax->registerFunction("isOddOrEven");
Now we need to call this function when the user types in the text input. We don't want the user to have to click any buttons in order to send off the request, so the most obvious approach is to attach the xajax function to the onkeyup event of the text input so that as the user types the data is sent to the server and the function is called.
<input id="myText" type="text" onkeyup="xajax_isOddOrEven(xajax.$(strId).value);" />
This may appear to work initially, especially if you are testing on localhost where the xajax responses come back very quickly. However, if you take this approach you will quickly learn that your application will have some problems.
The first problem is that every time the user types a letter, a request is sent off and the xajax function is called. For instance if the user types in the word "blatherskite", 12 separate xajax requests will be sent off and the isOddOrEven function will be called 12 times. Most of those those requests are unnecessary and put an undue burden on your server.
The second problem is that, because xajax is asynchronous, the requests may not come back in the same order as hey were sent. In other words, the xajaxResponse for the request for "blather" could possibly return after the request for "blatherskite" and so the "textInfo" element would display the word "Odd" even though the most recent text should display "Even".
The solution to both these problems is to delay calling the xajax function until the text has not changed for a reasonable amount of time. To do that we need some kind of buffering mechanism. I have created the following javascript class for that exact purpose.
<script type="text/javascript>
var OnKeyRequestBuffer =
{
bufferText: false,
bufferTime: 500,
modified : function(strId)
{
setTimeout('OnKeyRequestBuffer.compareBuffer("'+strId+'","'+xajax.$(strId).value+'");', this.bufferTime);
},
compareBuffer : function(strId, strText)
{
if (strText == xajax.$(strId).value && strText != this.bufferText)
{
this.bufferText = strText;
OnKeyRequestBuffer.makeRequest(strId);
}
},
makeRequest : function(strId)
{
xajax_isOddOrEven(xajax.$(strId).value);
}
}
</script>
This class will only execute the code in the OnKeyRequestBuffer.makeRequest function if the text in the input with the given id has not changed in a half of a second (500 ms). So now, instead of calling the xajax function directly in the onkeyup event, we call our buffer class:
<input id="myText" type="text" onkeyup="OnKeyRequestBuffer.modified('myText');" />
Now the xajax request is not sent unless the user has not modified the text in the last half of a second. Using this method we only send out necessary requests, our server is spared the extra load, and we avoid most out of order responses to asynchronous responses sent in rapid succession. You can adjust the time period the class will wait before sending off the request by modifying the vaue of the bufferTime parameter of the class.
So here is the complete example program:
<?php //include the xajax class require_once("xajax.inc.php"); $xajax = new xajax(); function isOddOrEven($strText) { $objResponse = new xajaxResponse(); $objResponse->assign("textInfo", "innerHTML", (strlen($strText)%2==0?"Even":"Odd")); return $objResponse; } $xajax->registerFunction("isOddOrEven"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd"> <html> <head> <?php $xajax->printJavascript(); ?> <script> var OnKeyRequestBuffer = { bufferText: false, bufferTime: 500, modified : function(strId) { setTimeout('OnKeyRequestBuffer.compareBuffer("'+strId+'","'+xajax.$(strId).value+'");', this.bufferTime); }, compareBuffer : function(strId, strText) { if (strText == xajax.$(strId).value && strText != this.bufferText) { this.bufferText = strText; OnKeyRequestBuffer.makeRequest(strId); } }, makeRequest : function(strId) { xajax_isOddOrEven(xajax.$(strId).value); } } </script> </head> <body> <input type="text" id="myText" onkeyup="OnKeyRequestBuffer.modified('myText');"> <div id="textInfo"></div> </body> </html>