Custom Search

Friday, November 27, 2009

How Ajax Works -1

How Ajax Works -1
--------------------------
AJAX depends on XmlHttpRequest. It was originally added to Microsoft Internet Explorer 5 as an ActiveX object, and has since been added to other browsers as a built-in JavaScript object. XmlHttpRequest will submit a request to a web server where the enclosing page is stored and return the results so that they can be used within the web page that made the XmlHttpRequest request.

Originally, XmlHttpRequest was intended to retrieve XML documents from the server, but in actuality it can retrieve any content as long as it's text. You can then incorporate the results into your page using the DHTML techniques.

The first step in using XmlHttpRequest is creating the object.Internet Explorer and other browsers handle XmlHttpRequest differently, so you have to use the capability detection features. This also enables you to avoid running into problems with browsers that don't support XmlHttpRequest at all. Here's the code:

if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}

First I check to see whether the browser provides XmlHttpRequest as a property of the window object. If it does (as browsers other than Internet Explorer do), I use the new keyword to create a new XmlHttpRequest object. If it does not, I check to see whether the browser supports the ActiveXObject property of window. Only Internet Explorer provides that feature, so if that check returns true, I can create an XmlHttpRequest object using ActiveX. The XmlHttpRequest object, once created, works the same in all browsers that support it. Here's how you use it to retrieve information from the server:

request.onreadystatechange = processReadyStateChange;
request.open("POST", "remote.cgi", true);
request.send("user=test");

I'll explain the first line last. The second line is used to specify the request method and URL for the connection. The first argument, "POST" in this example, is the request method to use. You can use "GET" or "POST" here, just as you can with the action attribute of the <form> element. The second argument is the URL. Since the request must go to the server where the page resides, you can just use a relative or absolute URL. There's no need to specify the server or protocol. In this case, the script would submit the request to remote.cgi in the same directory as the page containing this code. The final argument specifies whether the request should be asynchronous, and can be either TRue or false. You'll almost certainly want to use true here all the time. If you don't set the request to be asynchronous, the browser will wait for the request to complete before letting the user do anything.

Once you've created the connection, you need to send data over the connection using the send() method. If you use the GET method, you can just use an empty string ("") here. If you use POST, you'll include the actual data to send with the request as the argument to the send() method. Once again, think about the request as a form submission. You can gather data from form elements on the page and pass it to send() to submit the form via XmlHttpRequest rather than submitting the form itself. The data passed to send() should be encoded using URL encoding. After the data is submitted, your script has to handle the response from the server. That's where the first line comes in. In order to deal with the response, you have to register a function to handle events associated with XmlHttpRequest. You'd think that you could just write some JavaScript to handle the results and put it in your script after the line that sends the data to the server, but that's not how XmlHttpRequest works. Remember that I mentioned that XmlHttpRequest can be used asynchronously. What that means is that once the script sends the request, your code can go on and do other things while the browser deals with handling the results of the request.

The browser processes the response by generating events. If you want to do anything with the results, you have to register a function as the handler for those events. If you wanted to register a handler for an onclick event for a link, you could use this code:
<a href="/" id="mylink" onclick="linkClicked()">My link</a>

There's another way to register a handler as well, entirely within a script. If you wanted to use JavaScript to register the event handler for the link, which I helpfully gave the ID mylink, you could do it like this:
document.getElementById("mylink").onclick = linkClicked;

One thing to note is that I don't include the () after linkClicked in the JavaScript example. That's because I want to associate the function named linkClicked with that event. If I include the parentheses, the script will actually call the function and assign the results to the onclick property. I want the function itself in this case.
OK, back to XmlHttpRequest. As I mentioned, the browser handles the response by generating events. I specified the handler for those events on this line:
request.onreadystatechange = processReadyStateChange;

That line says that onreadystatechange events for the XmlHttpRequest object should be passed to a function named processReadyStateChange. When a response is being processed, it goes through multiple states before it's finished.

Table : XmlHttpRequest States
State Description
0 --> The open() method has not been called.
1 --> The send() method has not been called.
2 --> The send() method has been called but the response headers have not been sent back.
3 --> Some response data has been received.
4 --> All of the response data has been received.

As you can probably guess, the states progress from 0 to 4. The function you associate with onreadystatechange is called every time the state advances. Here's what such a function looks like:
function onreadystatechange() {
if (request.readyState == 4) {
window.alert("Finished!");
}
}


This function examines the readyState property of the XmlHttpRequest object to see what the current state of the request is. This function will be called once for every state change, but it doesn't do anything until state 4 is reached and the request is finished. At that point, it just displays an alert. Most handlers will be written like this because the only state you care about is state 4. In addition to readyState, XmlHttpRequest has other properties, which are listed in below table.

Table : XmlHttpRequest Properties
Property Description
onreadystatechange --> The function specified to handle state change events
readyState --> The current ready state for the object
responseText --> The response sent by the server
status The --> HTTP status code of the response
statusText --> The text message associated with the HTTP status

Once you've reached readyState 4, you can access the data passed back from the server via the responseText property and deal with it as you wish.

An AJAX Example
-------------------------
In this example, I've created a page that allows you to update the current temperature by pressing a button. I use XmlHttpRequest to retrieve the current temperature, and use JavaScript to replace a <div> on the page with data from the server. Here's the source code for the page:

-----------------------test.html

<html xmlns="http://www.w3.org/1999/xhtml" version="-//W3C//DTD XHTML 1.1//EN"
xml:lang="en">
<head>
<title>AJAX Example</title>
<script language="JavaScript">
var request = false;

function sendAjaxRequest(toUrl) {
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}

if (request) {
request.onreadystatechange = processReadyStateChange;
request.open('GET', toUrl, true);
request.send("");
}
}

function updateTemperature(msg) {
var contentDiv = document.getElementById("ajaxTarget");
contentDiv.innerHTML = msg;
}

function getLatestTemp() {
sendAjaxRequest("temp.txt");
}

function processReadyStateChange() {
if (request.readyState == 4) {
if (request.status == 200) {
updateTemperature(request.responseText);
}
else {
alert("An error occurred.");
}
}
}
</script>
</head>

<body>
<p>
Current temperature:
<div id="ajaxTarget" style="font-size: x-large;">90 degrees</div>
</p>

<p>
<button onclick="getLatestTemp()">Update Temperature</button>
</p>
</body>
</html>

--------------------test.txt
55 degree

----------------------------
As you can see, the HTML section of the page is relatively short. All I have is a paragraph containing a <div> that contains the current temperature and another paragraph with a button that's used to update the temperature.
When the user clicks on the Update Temperature link, the function specified in the onclick handlergetLatestTemp()is called. That function contains a single line of code:
sendAjaxRequest("temp.txt");

This code just calls another function I wrote called sendAjaxRequest(). The argument is the URL for the content on the server. Ordinarily, the URL would point to a script that looks up the current temperature and transmits it back to the user. In this case, I have a text file on the server in the same directory as this page, and XmlHttpRequest is happy to retrieve it. The temp.txt file contains only the following text:
55 degrees

The code in the sendAjaxRequest() function should look familiar, since I just explained how it works. I create a new XmlHttpRequest object, assign a handler to the onreadystatechange event, open the connection, and send the request data. One thing you might notice is that I declare the request variable at the top level of my script rather than within my function. That's so that the variable is visible to the handler function as well as to the function where it is assigned.
I also test to make sure that my attempts to create the XmlHttpRequest object were successful prior to calling any of its methods. That way I won't produce errors in older browsers that don't support XmlHttpRequest. In this script, my event handling function does a lot more than the previous one. Here's the source:
function processReadyStateChange() {
if (request.readyState == 4) {
if (request.status == 200) {
updateTemperature(request.responseText);
}
else {
alert("An error occurred.");
}
}
}

As in the preceding code, the script only cares about readyState 4. It ignores all of the state changes leading up to it. Once readyState 4 has been reached, it checks the status property of the XmlHttpRequest object. A status of 200 means that the request was successful and the script received the text it wants. If the status is anything else, an error message is displayed. If the request was successful then the script calls the updateTemperature function, passing in the response text as an argument.
In this case, temp.txt contains only the temperature to be displayed. More involved scripts could produce complex data structures represented as XML that the page has to unpack, but in this example I just want to take the result and display it. That's what updateTemperature() is for:
function updateTemperature(msg) {
var contentDiv = document.getElementById("ajaxTarget");
contentDiv.innerHTML = msg;
}

The code uses the getElementById() function to obtain a reference to the <div> on the page. It then replaces its current contents with the response text using the innerHTML property.
As I said before, a real-life example would be significantly more complex, but this example illustrates how AJAX is used in a simple case. Unlike the other examples you've seen in this book so far, you'd have to put both the HTML page and temp.txt file on a web server in order for the example to work. XmlHttpRequest relies on the HTTP protocol, and its security constraints require the target to be on the same server as the page making the call.

====================================================

No comments:

Post a Comment