Dynamically Fetching Data without Refreshing (XMLHttpRequest)

it became boring to input data and then press that damn "Submit" button over and over everytime we want to add or look for something!
but we are not going to stay there accepting this anymore, are we? :)

NOTE: this articles assumes that you have basic knowladge of javascript and PHP.

in this tutorial, we will be looking at the revolutionary XMLHttpRequest object which allows us to send and receive data dynamically without the need of refreshing the page.
This technology was first introduced by Microsoft in Internet Explorer 5 as an ActiveX branch then FireFox 1.0, Netscape 7 and Safari 1.2 followed.

To instantiate an XMLHttpRequest object you have to write this for IE users:

 var req = new ActiveXObject("Microsoft.XMLHTTP");

For other compatible browsers:

 var req = new XMLHttpRequest;

the XMLHttpRequest object has the following methods:

We will be using open() and send() method all the time mainly!
the open() method takes 5 arguments 3 of them are optional.
the first 2 arguments are the method (GET or POST) and the URL to which you are going to send the request.
The send() method will, obviously, send the request.


Let's look at this example to clear things up.
Let's assume we have a phonebook and all data are stored in a MySQL table and we want to make a search page where the user enters a number and the script should check if the number exists in the database or not.
If the number was found, will display the name of our contact otherwise we will show "Not found!" message.
all that without even reloading the page after submition!

So first let's take a look at the table structure (let's name numbers):

 CREATE TABLE `numbers` ( 
  `cells` int(15) unsigned NOT NULL default '0', 
  `name` tinytext NOT NULL, 
  PRIMARY KEY  (`cells`) 
);

We have created a table with 2 fields: cells and name
"cells" as a primary key.
Now let's take a look at our magic function which will fetch the data without refreshing:


var req; 
var oldData; 
var doesNotSupport = true; 
 
function getNumber(url, number) 
{ 
    if (number == "" || oldData == number || !doesNotSupport) 
        return; 
 
    oldData = number; 
    document.getElementById('result').value = "Searching ..."; 
 
    if (window.XMLHttpRequest) { 
        req = new XMLHttpRequest; 
    } else if (window.ActiveXObject) { 
        req = new ActiveXObject("Microsoft.XMLHTTP"); 
    } 
     
    if (req) { 
       req.onreadystatechange = processReqChange; 
       req.open("GET", url + '?number=' + number, true); 
       req.send(null); 
    } else { 
       alert("Your browser does not support XMLHttpRequest technology!"); 
       doesNotSupport = false; 
    } 
}

We have defined a function which take 2 arguments: url and number
the "url" argument will take the URL to which we will send the request and the "number" argument is the number we are looking for.

we also want to prevent the script from sending a new request if the number was the same as before! so we defined the variable oldData which will save the last number entered and compare it to the new number entered to the form if it was the same, it will quit and will not send a new request:

     if (number == "" || oldData == number || !doesNotSupport) 
        return;

we also don't want to send a request if the number was empty!
but what about this doesNotSupport variable? the first time the script runs it will hold "true" and then try to send the request! if the XMLHttpRequest object was not found or couldn't be instantiated, we will alert the user and set the value to "false" in:

    } else { 
       alert("Your browser does not support XMLHttpRequest technology!"); 
       doesNotSupport = false; 
    }

so if the user tried to enter a new number to force the request to be resent it will refuse to bother trying to send the request again :p

if the user could pass the condition above, then we assign the current number to be queried to the variable oldData and display the word "Search..." to make it look dynamic:

    oldData = number; 
    document.getElementById('result').value = "Searching ..."; 

The onreadystatechange property is an event handler which fires a function when the the state changes:

       req.onreadystatechange = processReqChange; 

We declared that when the state changes, processReqChange() function should be invoked. We will see the definition of this function later.

It's worth saying that when a request is sent these properties are populated:

readyState holds the object status (as integer):

now let's take a look at the processReqChange() function definition:

function processReqChange() { 
    // only if req shows "loaded" 
    if (req.readyState == 4) { 
        // only if "OK" 
        if (req.status == 200) { 
            document.getElementById('result').value = req.responseText; 
        } else { 
            alert("There was a problem retrieving the data:\n" + req.statusText); 
        } 
    } 
}

This function will check if the readyState is 4 (completed) and status is "200" (OK) to display the result in the field "result".
Here is the form we are using:

<style type="text/css">
#result {
  background-color: transparent;
  border: 1px dashed gray;
  font-family: tahoma;
  text-align: center;
  color: red;
  letter-spacing: 2.5px;
}
</style> 
<form> 
<label for="result">Name:</label> 
<input type="text" id="result" name="result" size="20" disabled="disabled" /><br /> 

<label for="mobile">Cell number:</label> 
<input type="text" name="mobile" onblur="getNumber('getnumber.php', this.value);" id="mobile" /> 
</form>

The result field will invoke the function getNumber() when ever it loses fox and it passes the URL (getnumber.php) and its value (this.value)

Here is how our getnumber.php looks:

<?php
$number = (int) $_GET['number']; //takes the number from URL

if (empty($number))
   die;

$server   = 'SERVER'; 
$username = 'USERNAME';
$password = 'PASSWORD';
$database = 'DATABASE';


$link = mysql_connect($server, $username, $password);
mysql_select_db($database);

$fetch = mysql_query("SELECT name FROM numbers WHERE cells='$number'")or
die(mysql_error());

$num = mysql_num_rows($fetch);

if (empty($num))
   $send = 'Not found';
else
   $send = mysql_result($fetch, 0, 'name');


header("Content-type: text/plain");
echo $send;
?>

This simple script will take the number from the URL (i.e. getnumber.php?number=5454014) and then checks it in the database.
if the name was not found, we will print "Not found!" otherwise we print the name.

Our javascript function will take what has been printed (the answer to the request) and put it in responseText property. You can however, use the responseXML property when your answer to the request is XML.

That's all!
you can view the script live at: XMLHTTPRequest.htm

NOTE: in order to see this script in action, you have to enable javascript and your browser should be one of the compatible browsers with XMLHttpRequest technology.

try to input the number 123456789 and you should see "from1To9" in the result field. Any other number will display Not found!

* Many details were inspired and taken from: http://developer.apple.com/internet/webcontent/xmlhttpreq.html

Saleh Jamal


Article posted in http://forum.worldofphp.com in May 20, 2005  [http://www.phpsimplicity.com]