You are on page 1of 10

AJAX - Basic

Project1: ONLINE CLASS VIEWER


Ti liu hng dn K thut AJAX
1.

Gii thiu
Bnh thng, mi khi browser gi 1 yu cu ln server th n phi reload li trang web, tc l
yu cu server gi li ton b trang web.
K thut Ajax (Asynchronous Javascript And Xml) gip cho browser c th gi yu cu n
server v nhn response m khng cn reload li trang web. Ngoi ra, request ny c th c
thc hin 1 cch bt ng b ( trong qu trnh thc hin request, ngi dng vn c th tng
tc vi trang web)
K thut ny s dng i tng XMLHttp thc hin cc truy vn ln server.

2.

S dng lp XMLHttp
Ta s s dng javascript thao tc trn i tng XMLHttp.

2.1. To i tng XMLHttp:


Bc u tin cn phi thc hin trong vic s dng i tng XMLHttp l phi to n.
i vi cc trnh duyt khc nhau th vic to i tng ny s khc nhau.
i vi Internet Explorer (IE), i tng ny c ci t di dng 1 ActiveXObject.
Do , to c n, cn phi thc hin cu lnh javascript sau:
var oXmlHttp = new ActiveXObject("Microsoft.XMLHttp");

Trong Microsoft.XMLHttp l loi i tng ActiveXObject cn to.


Tuy nhin, c nhiu phin bn IE khc nhau nn i tng XMLHttp cng c nhiu
phin bn khc nhau.
Cc phin bn ny l:

Microsoft.XMLHttp

MSXML2.XMLHttp

MSXML2.XMLHttp.3.0

MSXML2.XMLHttp.4.0

MSXML2.XMLHttp.5.0

vit 1 on code tng qut, c th s dng cho bt k phin bn IE no, ta s dng cu


lnh try catch

AJAX - Basic

i vi cc trnh duyt : Mozilla Firefox, Safari, v Opera th cu lnh javascript to


i tng XMLHttp ging nhau:
var oXmlHttp = new XMLHttpRequest();

Nh vy, to c i tng XMLHttp cho mi trnh duyt ta dng on javascript


sau:

AJAX - Basic

2.2. S dng i tng XMLHttp


Sau khi to i tng XMLHttp, ta bt u thc hin vic to request n server. Bc
u tin l gi phng thc open, dng khi to i tng. Phng thc ny nhn vo
3 tham s:
Request Type: l 1 chui cho bit loi request cn thc hin, c th l GET hoc
POST.
URL: l chui URL cho bit a ch cn gi request n.
Async: l 1 gi tr boolean, cho bit request c c thc hin 1 cch bt ng b
hay khng.
Tham s ny rt quan trng, n xc nh cch thc m javascript thc hin request. Khi
c thit lp l true, request s c thc hin 1 cch bt ng b, v cc on lnh
javascript vn tip tc c thc hin m khng cn phi ch response t server. V vy,
ta cn phi ci t 1 hm x l s kin c nhim v ch response t server. Nu async l
false th cc on lnh javascript k tip s khng c thc hin cho n khi server gi
xong d liu v. Nu nh thi gian m server tr response v l lu th s gy bt tin v
ngi dng khng th tng tc c vi trang web trong khong thi gian . V vy,
cch tt nht l gn cho async gi tr True khi gi hm open.
V d: thc hin 1 request yu cu server tr v ni dung file info.txt nm trn th
mc cha trang web trn server th ta thc hin nh sau:
oXmlHttp.open("get", "info.txt", true);

i tng XMLHttp c 1 thuc tnh l readyState, tham s ny s thay i khi m


request c thc hin v khi client nhn c response t server. Thuc tnh ny c 5
gi tr nh sau:

0 (Uninitialized): i tng mi c to nhng hm open cha c gi.


1 (Loading): Hm open mi c gi nhng request cha c gi
2 (Loaded): Request va mi c gi
3 (Interactive): Client nhn c mt phn response t server
4 (Complete): Tt c d liu c server gi v client v kt ni ng li.

Mi ln thuc tnh readyState thay i gi tr th s kin readystatechange c pht


sinh v hm x l s kin onreadystatechange c gi. Do cc browser ci t i
tng XMLHttp khc nhau nn m bo trang web ca mnh c th chy c trn
nhiu browser th ta ch nn dng cc gi tr sau ca thuc tnh readyState: 0, 1 v 4
Trong hu ht cc trng hp, ta ch cn xt trng hp thuc tnh readyState c gi tr l
4, tc l khi ton b d liu t server gi n client.

AJAX - Basic
Trong on lnh trn, ta nh ngha 1 hm onreadystatechange c chc nng hin th 1
dialog box thng bo.
Bc cui cng l gi hm send(), hm ny s thc s gi request ln server. Hm ny
c 1 tham s, l chui cha phn body ca request. i vi request loi GET th
khng cn phn body ny, do , ta gi hm send vi tham s l NULL. i vi loi
request l POST th tham s ny khc null.
oXmlHttp.send(null);

Sau khi gi hm ny th request c gi i, khi ton b d liu c nhn v th hm


onreadystatechange s c gi v y, ta s thc hin cc x l tng ng vi d liu
nhn c. D liu ny c ly thng qua 1 trong 2 thuc tnh responseText hoc
responseXML.
Thuc tnh responseText cha chui response trong khi responseXML cha 1 i tng
ti liu XML. Thuc tnh responseXML ch c dng khi loi d liu tr v l text/xml.
Trong trng hp yu cu ni dung file info.txt trong v d trn th ta ch cn dng thuc
tnh responseText.
Nu s dng thuc tnh responseXML th cn tm hiu thm v DOMDocument v
responseXML chnh l 1 i tng DOMDocument. C th tm thng tin v loi i
tng ny trong MSDN 2003 vi t kha DOMDocument.
Mt on code v d s dng thuc tnh responseXML
var xmldoc = httpRequest.responseXML;
var root_node = xmldoc.getElementsByTagName(root).item(0);
alert(root_node.firstChild.data);

Cc vn khc
Mt vn na c t ra l, sau khi thc hin, c th request khng thnh cng. Chng
hn nh, nu ta yu cu server tr v ni dung file info.txt nhng trn server khng c
file ny th li s pht sinh.
gii quyt trng hp b li, ta dng 2 thuc tnh khc ca lp XMLHttp l status v
statusText. Nu status c gi tr l 200 th request thnh cng, ngc li, request tht
bi, khi , thng tin li s c cha trong thuc tnh statusText.
Sau khi nhn response t server (readyState = 4), c th kim tra request thnh cng hay
khng bng on code.

Ngoi d liu nhn c trong phn body ca response bng 2 thuc tnh responseText
hoc responseXML, ta c th truy xut n d liu trong phn header ca response bng

AJAX - Basic
hm getResponseHeader. Phn thng tin quan trng nht trong response header l
Content-Type, phn ny cho bit d liu ly v thuc loi g (text, html, image...)

Cng c th ly tt c cc thng tin t response header nh sau:

Trong khi thc hin request, ta cng c th thm cc thng tin vo phn header ca
request, y c th l cc thng tin bt k.
oXmlHttp.setRequestHeader("myheader", "myvalue");
oXmlHttp.send(null);

AJAX - Basic

Ph lc
Tham kho thm v vic gi GET request v POST request trong ni dung di y
(trong ny c c phn code ca server side)

1.

XMLHttp GET Requests

It's time to revisit the hidden frame GET example to see how the process could be improved using
XMLHttp. The first change will be to GetCustomerData.php, which must be changed from an HTML
page to simply return an HTML snippet. The entire file now becomes streamlined:
<?php
header("Content-Type: text/plain");
$sID = $_GET["id"];
$sInfo = "";
$sDBServer = "your.databaser.server";
$sDBName = "your_db_name";
$sDBUsername = "your_db_username";
$sDBPassword = "your_db_password";
$sQuery = "Select * from Customers where CustomerId=".$sID;
$oLink = mysql_connect($sDBServer,$sDBUsername,$sDBPassword);
@mysql_select_db($sDBName) or $sInfo="Unable to open database";
if($oResult = mysql_query($sQuery) and mysql_num_rows($oResult) > 0) {
$aValues = mysql_fetch_array($oResult,MYSQL_ASSOC);
$sInfo = $aValues['Name']."<br />".$aValues['Address']."<br />".
$aValues['City']."<br />".$aValues['State']."<br />".
$aValues['Zip']."<br /><br />Phone: ".$aValues['Phone']."<br />".
"<a href=\"mailto:".$aValues['E-mail']."\">".
$aValues['E-mail']."</a>";
} else {
$sInfo = "Customer with ID $sID doesn't exist.";
}
mysql_close($oLink);
echo $sInfo;

?>

As you can see, there are no visible HTML or JavaScript calls in the page. All the main logic remains
the same, but there are two additional lines of PHP code. The first occurs at the beginning, where the
header() function is used to set the content type of the page. Even though the page will return an
HTML snippet, it's fine to set the content type as text/plain, because it's not a complete HTML page
(and therefore wouldn't validate as HTML). You should always set the content type in any page that is
sending non-HTML to the browser. The second added line is towards the bottom, where the $sInfo
variable is output to the stream by using the echo command.

AJAX - Basic
In the main HTML page, the basic setup is this:
<p>Enter customer ID number to retrieve information:</p>
<p>Customer ID: <input type="text" id="txtCustomerId" value="" /></p>
<p><input type="button" value="Get Customer Info"
onclick="requestCustomerInfo()" /></p>
<div id="divCustomerInfo"></div>
The requestCustomerInfo() function previously created a hidden iframe but now must
be changed to use XMLHttp:
function requestCustomerInfo() {
var sId = document.getElementById("txtCustomerId").value;
var oXmlHttp = zXmlHttp.createRequest();
oXmlHttp.open("get", "GetCustomerData.php?id=" + sId, true);
oXmlHttp.onreadystatechange = function () {
if (oXmlHttp.readyState == 4) {
if (oXmlHttp.status == 200) {
displayCustomerInfo(oXmlHttp.responseText);
} else {
displayCustomerInfo("An error occurred: " +
oXmlHttp.statusText);
}
}
};
oXmlHttp.send(null);
}

Note that the function begins the same way, by retrieving the ID the user entered. Then, an XMLHttp
object is created using the zXml library. The open() method is called, specifying an asynchronous
GET request for GetCustomerData.php (which has the aforementioned ID added to its query string).
Next comes the assignment of the event handler, which checks for a readyState of 4 and then checks
the status of the request. If the request was successful (status of 200), the displayCustomerInfo()
function is called with the response body (accessed via responseText). If there was an error (status
is not 200), then the error information is passed to displayCustomerInfo().
There are several differences between this and the hidden frame/iframe example. First, no JavaScript
code is required outside of the main page. This is important because any time you need to keep code in
two different places there is the possibility of creating incompatibilities; in the frame-based examples,
you relied on separate scripts in the display page and the hidden frames to communicate with one
another. By changing GetCustomerInfo.php to return just the data you're interested in, you have
eliminated potential problems with JavaScript calling between these locations. The second difference is
that it's much easier to tell if there was a problem executing the request. In previous examples, there
was no mechanism by which you could identify and respond to a server error in the request process.
Using XMLHttp, all server errors are revealed to you as a developer, enabling you to pass along
meaningful error feedback to the user. In many ways, XMLHttp is a more elegant solution than hidden
frames for in-page HTTP requests.

2.

XMLHttp POST Requests

Now that you've seen how XMLHttp can simplify GET requests, it's time to take a look at POST
requests. First, you need to make the same changes to SaveCustomer.php as you did for

AJAX - Basic
GetCustomerInfo.php,

which means you need to remove extraneous HTML and JavaScript, add the
content type information, and output the text:
<?php
header("Content-Type: text/plain");
$sName = $_POST["txtName"];
$sAddress = $_POST["txtAddress"];
$sCity = $_POST["txtCity"];
$sState = $_POST["txtState"];
$sZipCode = $_POST["txtZipCode"];
$sPhone = $_POST["txtPhone"];
$sEmail = $_POST["txtEmail"];
$sStatus = "";
$sDBServer = "your.database.server";
$sDBName = "your_db_name";
$sDBUsername = "your_db_username";
$sDBPassword = "your_db_password";
$sSQL = "Insert into Customers
(Name,Address,City,State,Zip,Phone,`E-mail`) ".
" values ('$sName','$sAddress','$sCity','$sState', '$sZipCode'".
", '$sPhone', '$sEmail')";
$oLink = mysql_connect($sDBServer,$sDBUsername,$sDBPassword);
@mysql_select_db($sDBName) or $sStatus = "Unable to open database";
if($oResult = mysql_query($sSQL)) {
$sStatus = "Added customer; customer ID is ".mysql_insert_id();
} else {
$sStatus = "An error occurred
while inserting; customer not saved.";
}
mysql_close($oLink);
?>

echo $sStatus;

This now represents the entirety of SaveCustomer.php. Note that the header() function is called to
set the content type, and echo is used to output $sStatus.
In the main page, the simple form that was set up to allow entry of new customer info is the following:
<form method="post" action="SaveCustomer.php"
onsubmit="sendRequest(); return false">
<p>Enter customer information to be saved:</p>
<p>Customer Name: <input type="text" name="txtName" value="" /><br />
Address: <input type="text" name="txtAddress" value="" /><br />
City: <input type="text" name="txtCity" value="" /><br />
State: <input type="text" name="txtState" value="" /><br />

AJAX - Basic
Zip Code: <input type="text" name="txtZipCode" value="" /><br />
Phone: <input type="text" name="txtPhone" value="" /><br />
E-mail: <input type="text" name="txtEmail" value="" /></p>
<p><input type="submit" value="Save Customer Info" /></p>
</form>
<div id="divStatus"></div>

You'll note that the onsubmit event handler has now changed to call the function sendRequest()
(although the event handler still returns false to prevent actual form submission). This method first
assembles the data for the POST request and then creates the XMLHttp object to send it. The data must
be sent in the format as a query string:
name1=value1&name2=value2&name3=value3

Both the name and value of each parameter must be URL-encoded in order to avoid data loss during
transmission. JavaScript provides a built-in function called encodeURIComponent() that can be used
to perform this encoding. To create this string, you'll need to iterate over the form fields, extracting and
encoding the name and value. The getRequestBody() function handles this:
function getRequestBody(oForm) {
var aParams = new Array();
for (var i=0 ; i < oForm.elements.length; i++) {
var sParam = encodeURIComponent(oForm.elements[i].name);
sParam += "=";
sParam += encodeURIComponent(oForm.elements[i].value);
aParams.push(sParam);
}
return aParams.join("&");
}

This function assumes that you will supply a reference to the form as an argument. An array (aParams)
is created to store each individual name-value pair. Then, the elements of the form are iterated over,
building up a string and storing it in sParam, which is then added to the array. Doing this prevents
multiple string concatenation, which can lead to slower code execution in some browsers. The last step
is to call join() on the array, passing in the ampersand character. This effectively combines all the
name-value pairs with ampersands, creating a single string in the correct format.
String concatenation in most browsers is an expensive process because strings are immutable, meaning
that once created, they cannot have their values changed. Thus, concatenating two strings involves first
allocating a new string and then copying the contents of the two other strings into it. Repeating this
process over and over causes a severe slowdown. For this reason, it's always best to keep string
concatenations at a minimum and use the array's join() method to handle longer string concatenation.
The sendRequest() function calls getRequestBody() and sets up the request:
function sendRequest() {
var oForm = document.forms[0];
var sBody = getRequestBody(oForm);
var oXmlHttp = zXmlHttp.createRequest();

AJAX - Basic
oXmlHttp.open("post", oForm.action, true);
oXmlHttp.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
oXmlHttp.onreadystatechange = function () {
if (oXmlHttp.readyState == 4) {
if (oXmlHttp.status == 200) {
saveResult(oXmlHttp.responseText);
} else {
saveResult("An error occurred: " + oXmlHttp.statusText);
}
}
};
oXmlHttp.send(sBody);
}

As with previous examples, the first step in this function is to get a reference to the form and store it in
a variable (oForm). Then, the request body is generated and stored in sBody. Next comes the creation
and setup of the XMLHttp object. Note that the first argument of open() is now post instead of get,
and the second is set to oForm.action (once again, so this script can be used on multiple pages). You'll
also notice that a request header is being set. When a form is posted from the browser to a server, it sets
the content type of the request as application/x-www-form-urlencoded. Most server-side languages
look for this encoding in order to parse the incoming POST data properly, so it is very important for it
to be set.
The onreadystatechange event handler is very similar to that of the GET example; the only change is
the call to saveResult() instead of displayCustomerInfo(). The last line is very important, as the
sBody string is passed to send() so that it will become part of the request body. This effectively
mimics what the browser does, so all server-side logic should work as expected.

3.

Advantages and Disadvantages of XMLHttp

Undoubtedly, you can see the advantage of using XMLHttp for client-server communication instead of
hidden frames. The code you write is much cleaner and the intent of the code is much more apparent
than using numerous callback functions with hidden frames. You have access to request and response
headers as well as HTTP status codes, enabling you to determine if your request was successful.
The downside is that, unlike hidden frames, there is no browser history record of the calls that were
made. The Back and Forward buttons do not tie in to XMLHttp requests, so you have effectively cut
off their use. It is for this reason that many Ajax applications use a mixture of XMLHttp and hidden
frames to make a truly usable interface.
Another disadvantage, which applies to Internet Explorer only, is that you depend on ActiveX controls
being enabled. If the user has your page set up in a particular security zone that doesn't allow ActiveX
controls, you cannot access the XMLHttp object. In that case, you may have to default to using hidden
frames.

You might also like