Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

One of the classic drawbacks to building a web application interface is that once a page has been downloaded to the client, the connection to the server is severed. Any attempt at a dynamic interface involves a full roundtrip of the whole page back to the server for a rebuild--a process which tends to make your web app feel inelegant and unresponsive. In this article, I'll be exploring how this problem can be tackled with the use of JavaScript and the XMLHttpRequest object.

I'm sure you're familiar with the traditional interface model for a web application. The user requests a page from the server, which is built and delivered to the browser. This page includes an HTML form element for capturing data from the user. Once the user posts their input back to the server, the next page can be built and served based on the input, and so the process continues. This is largely dictated by the nature of HTTP and differs from the traditional desktop application model of an interface which is inherently connected to the application layer.

Take the simple example of filling out a serial number box to register a desktop app on a platform like Microsoft Windows. According to convention, once you've finished typing that tiresome string of alphanumeric into the little boxes, a big green 'tick' icon appears to indicate you've entered a valid code. This happens instantly as a result of the interface being sewn to the application; as soon as you finish typing the number, the application is able to check its validity and respond.

Contrast this to the standard behavior of the same task represented through a web interface. Sure, all the boxes for keying in the serial number will look identical, but on completing input, the user would need to submit the page back to the server for the input to be validated. A new page would then load with a message to indicate success or failure, and on failure, the user would need to go back and try again ad infinitum.

So whilst it's not terribly common that a user would be asked to enter a serial number into a web application, there are countless other examples of user actions that can benefit from very fast reactions from the interface, and when the business logic is all the way back at the server, this can be difficult to achieve in a traditional web app.

Enter JavaScript

Through the use of JavaScript, a reasonable amount of logic can be added to an HTML page in order to give timely feedback to user interactions. This has some major drawbacks, however. The first problem is that, as the JavaScript has been delivered to the browser along with the page, that logic has been opened up to interrogation. This might be fine for checking the format of an email address but would be no good for something like our serial number example, as the exposure of the method of verifying that input would compromise the integrity of the serial number mechanism.

The second problem with including any serious logic within the page is that the interface layer is simply not the place for serious logic. This belongs in the application layer, which is way back at the server. The problem is compounded by the fact that JavaScript cannot usually be relied upon to be available at the client. Whilst the majority of users are able and willing to run JavaScript in their browser, a considerable number prefer not to, or browse with a device where JavaScript is either unavailable or makes no sense. Therefore, any logic operations performed with JavaScript at the client must be verified at the server in case the operation never occurred.

The XMLHttpRequest Object

A solution to these problem presents itself in the form of the XMLHttpRequest object. This object, first implemented by Microsoft as an ActiveX object but now also available as a native object within both Mozilla and Apple's Safari browser, enables JavaScript to make HTTP requests to a remote server without the need to reload the page. In essence, HTTP requests can be made and responses received, completely in the background and without the user experiencing any visual interruptions.

This is a tremendous boon, as it takes the developer a long way towards achieving the goals of both a responsive user interface and keeping all the important logic in the application layer. By using JavaScript to ferry input back to the server in real time, the logic can be performed on the server and the response returned for near-instant feedback.

The Basics

Due to its history, and not yet being embodied in any public standard (although something similar is in the works for the proposed W3C DOM Level 3 Load and Save spec), there are two distinct methods for instantiating an XMLHttpRequest object. For Internet Explorer, an ActiveX object is used:

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

For Mozilla and Safari, it's just a native object:

var req = new XMLHttpRequest();

Clearly, as a result of this inconsistency, it's necessary to fork your code based on support for the appropriate object. Whilst there are a number of methods for doing this (including inelegant browser hacks and conditional comment mechanisms), I believe it's best to simply test for support of either object. A good example of this can be found in Apple's developer documentation on the subject. Let's take their example:

var req;

function loadXMLDoc(url) 
{
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
        req.onreadystatechange = processReqChange;
        req.open("GET", url, true);
        req.send(null);
    // branch for IE/Windows ActiveX version
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
        if (req) {
            req.onreadystatechange = processReqChange;
            req.open("GET", url, true);
            req.send();
        }
    }
}

A particularly important property to note is the onreadystatechange property. Note how it is assigned to a function processReqChange. This property is an event handler which is triggered whenever the state of the request changes. The states run from zero (uninitialized) through to four (complete). This is important because our script isn't going to wait for the response before continuing. The HTTP shenanigans are initiated, but then they carry on out of process whilst the rest of the script runs. Due to this, it's not as simple as having loadXMLDoc return the result of the request at the end of the function, because we don't know if we'll have a response by then or not. By having the function processReqChange check for the state changing, we can tell when the process has finished and carry on only if it has been successful.

With this in mind, a skeleton processReqChange function needs to check for two things. The first is the state changing to a value of 4, indicating the process complete. The second is to check the HTTP status code. You'll be familiar with common status codes like 404 (file not found) and 500 (internal server error), but the status code we're looking for is good old 200 (ok), which means everything went well. If we get both a state of 4 and an HTTP status code of 200, we can go right ahead and start processing the response. Optionally, of course, we can attempt to handle any errors at this point, if, for example, the HTTP status code was something other than 200.

function processReqChange() 
{
    // only if req shows "complete"
    if (req.readyState == 4) {
        // only if "OK"
        if (req.status == 200) {
            // ...processing statements go here...
        } else {
            alert("There was a problem retrieving 
               the XML data:\n" + req.statusText);
        }
    }
}

In Practice

I'm going to work up a practical example so we can get this going. Most web applications have some method of signing up users, and it's common to ask the user to pick a username to use for the site. Often, these need to be unique, and so a check is made against the database to see if any other user already has the username a new recruit is trying to sign up with. If you've ever signed up for a web mail account, you'll know how infuriating it is cycling around the process trying to find a username that isn't already taken. It would be really helpful if that check could be made without the user leaving the page.

The solution will involve four key elements: an XHTML form, a JavaScript function for handling the specifics of this case, our pair of generic functions (as above) for dealing with HTTP, and finally, a script on the server to search the database.

The Form

Here's the easy bit--a simple form field to collect the user's chosen username. An onblur event handler is used to fire the script. In order to display a friendly message to the user if the name is taken, I've embedded it in the form and hidden it with CSS. This should prove a little less violent than a standard JavaScript alert box.

<input id="username" name="username" type="text" 
  onblur="checkName(this.value,'')" />
<span class="hidden" id="nameCheckFailed">
  This name is in use, please try another. 
</span>

The CSS defines a class for hidden and also one for showing the error. Call that one error.

span.hidden{
  display: none;
}

span.error{
  display: inline;
  color: black;
  background-color: pink;  
}

Handling the Input

The checkName function is used to handle the input from our form. Its job is to collect the input, decide which script on the server to present it to, invoke the HTTP functions to do the dirty work on its behalf, and then deal with the response. As such, this function has to operate in two modes. One mode receives input from the form, the other the response from the HTTP request. I'll explain the reason for this in the next section.

function checkName(input, response)
{
  if (response != ''){ 
    // Response mode
    message   = document.getElementById('nameCheckFailed');
    if (response == '1'){
      message.className = 'error';
    }else{
      message.className = 'hidden';
    } 
  }else{
    // Input mode
    url  = 
      'http://localhost/xml/checkUserName.php?q=' + input;
    loadXMLDoc(url);
  }

}

Our response is going to be easy to deal with--it'll be a string of either 1 or 0, with 1 indicating that the name is in use. Therefore, the function changes the class name of the error message so it gets displayed or hidden, depending. As you can see, the dirty work at the server is being done by a script called checkUserName.php.

HTTP Heavy Lifting

As we saw earlier, the HTTP work is being done by two functions, loadXMLDoc and processReqChange. The former can remain totally as-is for the purposes of this example, with the only modifications needed to the latter being a quick bit of DOM work.

You'll recall that by the time a successful response has been passed to processReqChange, we're no long in a position to pass any sort of return value back up the chain. Because of this, it's going to be necessary to make an explicit function call to another bit of code in order to do anything useful with the response. This is why our checkName function has to run in two modes. Therefore, the main job of processReqChange is to parse the XML coming back from the server and pass the raw values back to checkName.

However, it is important that we keep these functions generic (we may have multiple items on the page that need to make use of XMLHttpRequest), and so hard-coding a reference to checkName at this point would be foolhardy. Instead, a better design is to have the server indicate the handling function as part of its response.

<?xml version="1.0" encoding="UTF-8" 
  standalone="yes"?>
<response>
  <method>checkName</method>
  <result>1</result>
</response>

Parsing such a simple response should be no problem at all.

function processReqChange() 
{
    // only if req shows "complete"
    if (req.readyState == 4) {
        // only if "OK"
        if (req.status == 200) {
            // ...processing statements go here...
      response  = req.responseXML.documentElement;

      method    =
response.getElementsByTagName('method')[0].firstChild.data;

      result    = 
response.getElementsByTagName('result')[0].firstChild.data;

      eval(method + '(\'\', result)');
        } else {
            alert("There was a problem retrieving the XML 
                data:\n" + req.statusText);
        }
    }
}

By using the responseXML property of the XMLHttpRequest object, we have a ready-made XML object we can traverse with the DOM. By grabbing content of the method element, we know which local function to execute along with the result. Once you've finished testing, it's probably a good idea to dump the else clause from the above code, enabling the function to fail silently.

The Server Script

The final piece in our jigsaw is the script on the server to accept the request, process it, and return an XML document in response. For the purposes of our example, this script looks up usernames in a database table to determine whether a name is already in use. For brevity, my example PHP script below just checks against two hard-coded names, 'Drew' and 'Fred'.

<?php
header('Content-Type: text/xml');

function nameInUse($q)
{  
  if (isset($q)){
    switch(strtolower($q))
    {
      case  'drew' :
          return '1';
          break;
      case  'fred' :
          return '1';
          break;
      default:
          return '0';
    }
  }else{
    return '0';
  }
  
}
?>
<?php echo '<?xml version="1.0" encoding="UTF-8"
  standalone="yes"?>'; ?>
<response>
  <method>checkName</method>
  <result><?php 
    echo nameInUse($_GET['q']) ?>
  </result>
</response>

Of course, the logic used to verify the availability of the username in this script can be reused after the form is submitted to recheck that the name is available. This is an important step, since if JavaScript was not available at the client, this check would not have yet taken place. Additionally, on a busy site, a username which checked out OK at the time the user was filling the form in may have been taken by the time the form is submitted.

Perhaps as a next step, if you're interested in playing with this some more, you could add the ability for the server to return a list of suggested alternative usernames if the suggested name is taken.

In Conclusion

This small example really only scratches the surface of the things achievable with XMLHttpRequest. Some other examples would include Google Suggest, which uses XMLHttpRequest to provide suggested search terms, and the Ta-da Lists application, which commits user data to the server in the background to provide a really fast list managing interface. The real challenge here is not figuring out how to make the code work but thinking of interesting ways in which it can be utilized.

No Nonsense XML Web Development With PHP

Related Reading

No Nonsense XML Web Development With PHP
By Thomas Myer


Comment on this articleShare your experience in our forums.
(* You must be a
member of XML.com to use this feature.)
Comment on this Article


Titles Only Full Threads Newest First
  • chip oyun
    2008-04-24 11:27:48 oyun oyna [Reply]

    Chip Oyun (http://www.chipoyun.com)
    Oyun Oyna (http://www.chipoyun.com)


    http://www.chipoyun.com

  • Learn AJAX
    2007-11-06 07:06:25 Training-Connection [Reply]

    Looking to learn AJAX. Training Connection offers an intensive 3 day Ajax training in Chicago.


    For more information please click one the following links:


    http://www.trainingconnection.com
    http://www.trainingconnection.com/ajax-training.com

  • Header Output
    2007-02-13 00:20:37 tame_one [Reply]

    This drove me batty for three hours. For those like myself who are fluent in PHP but don't have a clue about AJAX, anything that would trip up an HTML document by modifying headers out of turn will also cause errors in AJAX. Difference is, you don't get the benefit of detailed error information.


    I kept getting "req.responseXML has no properties" until I figured that out. DOH! Hope this helps someone else.

  • Thanks
    2006-12-19 22:00:10 venkatramanan [Reply]

    Thanks Drew for the excellent article. I was struggling for a solution for the past two days and finally found it in your article
    Venkat

  • xmlHttpRequest could not be made
    2006-11-21 00:39:14 memen [Reply]

    Hi. pls i need someone's help cos i have a servlet and javascript already yet all i get is xmlHttp is null or not an object ANS THORWS A NULL POINTER EXCEPTION,


    sorry for pasting my codes i am working with a deadline which ends today and my boss is on my neck already.


    THIS IS MY HTML SIDE OF IT.
    <html>
    <head>
    <title> Dynamic Update</title>
    <script type="text/javascript">

    var xmlHttp;


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


    {
    xmlHttp = new XMLHttpRequest();
    }
    }
    function doStart()
    {
    createXMLHttpRequest();
    var url = "DynamicUpdate?task=res";
    xmlHttp.open("GET", url, true);
    xmlHttp.onreadystatechange = startCallback;
    xmlHttp.send(null);
    }



    function startCallback()
    {
    if(xmlHttp.readyState ==4)
    {


    if(xmlHttp.status ==200)
    {
    setTimeout("pollServer()",5000);
    refreshTime();
    }



    }


    }


    function pollServer()
    {
    createXMLHttpRequest();
    var url = "DynamicUpdate?task=foo";
    xmlHttp.open("GET", url, true);
    xmlHttp.onreadystatechange = pollCallback;
    xmlHttp.send(null);
    }


    function refreshTime()
    {
    var time_span = document.getElementById("time");
    var time_val = time_span.innerHTML;
    var int_val = parseInt(time_val);
    var new_int_val = int_val-1;
    if(new_int_val > -1)
    {
    Timeout(1000);
    timespan.innerHTML = new_int_val;
    }
    else
    {
    time_span.innerHTML = 5;
    }
    }


    function pollCallback()
    {
    if(xmlHttp.readyState ==4)
    {
    if(xmlHttp ==200)
    { var message = xmlHttp.responsexml.getElementByTagName("message")[0].firstChild.data;
    if(message != "done")
    {var new_row = createRow(message);
    var table = document.getElementById("dynamicUpdateArea");
    var table_body = table.getElementByTagName("tbody").item(0);
    var first_row = table_body.getElementByTagName("tr").item(1);
    table_body.isertBefore(new_row, first_row);
    setTimeout("pollServer()", 5000);
    refreshTime();


    }
    }
    }



    }
    function createRow (message)
    {
    var row = document.createElement("tr");
    var cell = document.createElement("td");
    var cell_data = document.createTextNode(message);
    cell.appendChild(cell_data);
    row.appendChild(cell);
    return row;


    }
    </script>
    </head>
    <body>
    <input type="button" value="launch" id="go" onClick="doStart()">
    <span id="time">5</span> seconds for refreshing Page
    <table id="dynamicUpdateArea" align="left">
    <tbody>
    <tr id="row0"><td></td></tr>
    </tbody>
    </table>


    </body>


    </html> THIS IS THE JAVA SERVLET
    /*
    * DynamicUpdate.java
    *
    * Created on 14 November 2006, 09:21
    */
    package AjaxDynamicServlet;


    import java.io.*;
    import java.net.*;
    import javax.servlet.*;
    import javax.servlet.http.*;


    /**
    *
    * @author Hilda
    * @version
    */


    public class DynamicUpdate extends HttpServlet {
    BufferedInputStream bis;
    private int counter = 1;
    /** Processes requests for both HTTP GET and POST methods.
    * @param request servlet request
    * @param response servlet response
    */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    String pageNum = request.getParameter("pageNum");

    response.setContentType("text/html;charset=UTF-8");

    if (pageNum.equals("1")){
    bis = new BufferedInputStream(new FileInputStream("C:\\Documents and Settings\\Administrator\\Desktop\\dynamicUpdate.html"));
    }

    }
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** Handles the HTTP GET method.
    * @param request servlet request
    * @param response servlet response
    */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    String res = "I actually have been trying this for some time now";
    String task = request.getParameter("task");
    String message = "";

    if (task.equals("res")){
    counter = 1;
    }else{
    switch (counter){
    case 1:message = "I actually have been trying this for some time now";break;
    case 2:message = "what? you say";break;
    case 3:message = "DYNAMIC page update of course";break;
    case 4:message = "It actually is turning into something else";break;
    case 5:message = "making me feel like a fish-brain";break;
    case 6:message = "o thou troubler of isreal";break;
    case 7:message = "done";break;
    }
    counter++;
    }
    res = "<message>" + message +"</message>";

    PrintWriter out = response.getWriter();
    response.setContentType("text/xml");
    response.setHeader("Cache-Control", "no-cache");
    out.println("<response>");
    out.println(res);
    out.println("</response>");
    out.close();



    }

    /** Handles the HTTP POST method.
    * @param request servlet request
    * @param response servlet response
    */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    processRequest(request, response);
    }

    /** Returns a short description of the servlet.
    */
    public String getServletInfo() {
    return "Short description";
    }
    // </editor-fold>
    }


  • Fantastic but it won't work for me with MYSQL?
    2006-07-15 18:39:36 rodent88 [Reply]

    Help, have been playing with this for the past 4 hours or so. Ahhhhhh. I want to source a MYSQL table instead in the php portion and create the XML statement on th fly like in the example. But it just is not working. Does anyone have an example???

  • Loading and Parsing XML using AJAX
    2006-06-11 18:33:58 LeProgrammeur [Reply]

    Hi,


    I posted a tutorial at www.KYNOU.com about Loading and Parsing XML with AJAX.
    Go to the link above and search for: Loading and Parsing XML with Ajax.
    Also in this website there is a chat room where I try to spend time answering questions. Feel free to stop by.

  • IE very slow processing
    2006-03-22 20:58:00 alexamies [Reply]

    I created an interactive web page allowing users to explore the hormones in the human body using the techniques in this article. It worked brilliantly in FireFox. However, in IE 6 it ran very slowly and in fact gave no response if the clicks did not allow the XML document to be fully parsed. It is a large page and the XML was fairly large as well. I had to convert the JavaScript arrays. DOM processing of the HTML document with IE is very slow as well. The page is at
    http://www.medicalcomputing.net/endocrine.html

  • My tribute - thankfully
    2006-01-05 13:25:10 _roro [Reply]

    Hi,


    written in PERL:
    http://rolfrost.de/cgi-bin/xmlhttpreq.cgi


    a simple demo for xmlhttprequest. This script makes a xmlhttprequest on yourself - see the htmlsource.


    --roro




  • Simple remote scripting library
    2006-01-02 20:45:40 joppinkaru [Reply]

    There is an open source, cross-browser php/javascript library, using a hidden iframe to perform database/server requests without refreshing the page, at


    http://simpletutorials.com/tutorials/jsrs/index.php


    For non-php users,


    http://www.ashleyit.com/rs/main.htm


    is very helpful.

  • Thank You
    2005-12-16 09:14:43 Stuart@xDox [Reply]

    I started programming for XML/SOAP in VBA & JavaScript about 4 months ago and reading this article, and the replies to it, have been more help than the about 3 foot of supposedly relevant books I have so far acquired.


    If anyone else is struggling with manipulating MS IXMLDOMs then these articles also helped me a lot - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/5bba501f-65c9-4d30-a555-afb325a6fc84.asp


    I get the drift of the argument over parsing XML DOMs being more complex - but surely the point is that if you *consistently* use XML at least you only have to get to grips with One DOM model and how to parse it - not Xteen different ones.


  • url problem
    2005-10-26 04:38:49 ramsee [Reply]

    Hi,
    I am writing the same code but try to run that code i have to give Url.
    I have created test.txt on D:
    so what url i am supposed to give thax

  • Probelm...
    2005-10-15 06:34:03 fretoune [Reply]

    Hello there,


    I'm sorry to say that I'm just unable to make the script work. It's been a couple of hours since it's driving me crazy... I've read over and over again, everything looks like what is above.
    I've tried without the quotes around (response == '1'), I've tried to put my files in the same folders... No way to work (I've got Firefox 1.0.7


    Sorry to post all my code, but if you can help, I'd greatly appreciate...


    file : loadxmldoc.js :
    var req;


    function loadXMLDoc(url) {
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
    req = new XMLHttpRequest();
    req.onreadystatechange = processReqChange;
    req.open("GET", url, true);
    req.send(null);
    // branch for IE/Windows ActiveX version
    } else if (window.ActiveXObject) {
    req = new ActiveXObject("Microsoft.XMLHTTP");
    if (req) {
    req.onreadystatechange = processReqChange;
    req.open("GET", url, true);
    req.send();
    }
    }
    }


    function processReqChange()
    {
    // only if req shows "complete"
    if (req.readyState == 4) {
    // only if "OK"
    if (req.status == 200) {
    // ...processing statements go here...
    response = req.responseXML.documentElement;
    method = response.getElementsByTagName('method')[0].firstChild.data;
    result = response.getElementsByTagName('result')[0].firstChild.data;
    eval(method + '(\'\', result)');
    } else {
    alert("There was a problem retrieving the XML data:\n" + req.statusText);
    }
    }
    }


    function checkName(input, response)
    {
    if (response != ''){
    // Response mode
    message = document.getElementById('nameCheckFailed');
    if (response == '1'){
    message.className = 'error';
    alert('ok');
    }else{
    message.className = 'hidden';
    alert('pas ok');
    }
    }else{
    // Input mode
    url = 'scripts/checkUserName.php?q=' + input;
    loadXMLDoc(url);
    }
    }


    file checkusername.php
    <?php
    header('Content-Type: text/xml');


    function nameInUse($q)
    {
    if (isset($q)){
    switch(strtolower($q))
    {
    case 'drew' :
    return '1';
    break;
    case 'fred' :
    return '1';
    break;
    default:
    return '0';
    }
    }else{
    return '0';
    }
    }
    ?>
    <?php echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'; ?>
    <response>
    <method>checkName</method>
    <result>
    <?php
    echo nameInUse($_GET['q']);
    ?>
    </result>
    </response>
    and the form has the span and the style required, with the call to the checkName function...


    Sorry for my incompetence... and thanks if you can help.


    Fred.


    PS : if I make an error in the name of the file checkusername.php, I've got the alert fine... so I guess my problem is in the response part ..?

  • XMLHTTP and java
    2005-10-07 13:17:44 vivekst [Reply]

    Hi,


    Im working on Java Servlets. How can I use XMLHttp with Servlets

  • XMLHTTP and java
    2005-10-07 12:19:56 vivekst [Reply]

    Hi,


    Im working on Java Servlets. How can I use XMLHttp with Servlets

  • Thanks for the very good introduction, however, ...
    2005-09-12 20:32:01 peterhf [Reply]

    when I run the app, the following message appears in the JavaScript Console and the app halts:


    Error: uncaught exception: Permission denied to create wrapper for object of class UnnamedClass


    I have gone over my html and php code and have some confidence that I have entered it correctly.


    I am using an iMac 10.3.9 and Firefox 1.0.6.


    Any thoughts?

  • Nice analysis
    2005-09-05 07:50:29 Auious [Reply]

    I'm glad to see your logical program and analysis in this article.
    Cre (http://www.cutegd.com/blog/)

  • I need help =(
    2005-08-22 22:29:43 chris99 [Reply]

    This is a revolution, no more waiting for requests!!
    I am totally new to this and the example is not working for me =( can someone help me?? pleaseeeee
    I created a file called revolution.html on my web server and another revolution.php. Mozilla doesn't do anything after I leave(onblur) the input form and explorer gives me a javascript error(it can't detect the object of the input box after I leave the box it says "Object expected")



    HTML BELOW



    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
    <title>This is a revolution</title>



    <style type="text/css">
    <!--


    span.hidden{
    display: none;
    }


    span.error{
    display: inline;
    color: black;
    background-color: pink;
    }
    --->
    </style>



    <SCRIPT LANGUAGE="JavaScript">


    var req;


    function loadXMLDoc(url)
    {
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
    req = new XMLHttpRequest();
    req.onreadystatechange = processReqChange;
    req.open("GET", url, true);
    req.send(null);
    // branch for IE/Windows ActiveX version
    } else if (window.ActiveXObject) {
    req = new ActiveXObject("Microsoft.XMLHTTP");
    if (req) {
    req.onreadystatechange = processReqChange;
    req.open("GET", url, true);
    req.send();
    }
    }
    }



    function processReqChange()
    {
    // only if req shows "complete"
    if (req.readyState == 4) {
    // only if "OK"
    if (req.status == 200) {
    // ...processing statements go here...
    response = req.responseXML.documentElement;


    method =
    response.getElementsByTagName('method')[0].firstChild.data;


    result =
    response.getElementsByTagName('result')[0].firstChild.data;


    eval(method + '(\'\', result)');
    } else {
    alert("There was a problem retrieving the XML data:\n" + req.statusText);
    }
    }



    function checkName(input, response)
    {
    if (response != ''){
    // Response mode
    message = document.getElementById('nameCheckFailed');
    if (response == 1){
    message.className = 'error';
    }else{
    message.className = 'hidden';
    }
    }else{
    // Input mode
    url =
    'http://revolution.php?q=' + input;
    loadXMLDoc(url);
    }


    }
    </SCRIPT>



    </head>



    <BODY >


    <input id="username" name="username" type="text"
    onblur="checkName(this.value,'')" >
    <span class="hidden" id="nameCheckFailed">
    This name is in use, please try another.
    </span>


    </body>
    </html>



    PHP file



    <?php
    header('Content-Type: text/xml');


    function nameInUse($q)
    {
    if (isset($q)){
    switch(strtolower($q))
    {
    case 'drew' :
    return '1';
    break;
    case 'fred' :
    return '1';
    break;
    default:
    return '0';
    }
    }else{
    return '0';
    }

    }
    ?>
    <?php echo '<?xml version="1.0" encoding="UTF-8"
    standalone="yes"?>'; ?>
    <response>
    <method>checkName</method>
    <result><?php
    echo nameInUse($_GET['q']) ?>
    </result>
    </response>





  • DWR
    2005-07-18 16:03:54 dmeany1 [Reply]

    This guy has done all the hard work with XMLHttpRequest() for you....if you use java.


    http://www.getahead.ltd.uk/dwr/

  • Microsoft.XMLHTTP vs. XMLHttpRequest
    2005-07-04 06:16:42 chrisward1 [Reply]

    This may be blinding obvious to everyone else - but I'd like to emphasise the importance of setting the header content type to "text/xml" if you are using the ActiveX XMLHTTP and want to get your hands on the DOM version of the returned XML.


    I've spent two days trying to track down why using Opera (using XMLHttpRequest) worked but using IE 6 (using Microsoft.XMLHTTP) didn't.


    My problem was that I'd done a copy/paste of an old servlet for my test and it set the content type to "text/html". In Opera this got through and the responeXML property returned with the expected DOM object, however IE6 did return the text (in the responseText property) but had a null responseXML.


    So don't forget...


    res.setContentType("text/xml");


    ... hope this helps someone out there!





  • char encoding problem
    2005-06-27 05:24:29 saidka [Reply]

    when requested server through XMLHttpRequest [open("GET","scr.php?par="+document.form.input.value,false)] i got (sorry for my english) next difficulty:
    FireFox converts values of form elements to utf-8 and sends as utf-8 when page opened directly by typing URL, otherwise (opened through link) sends as utf-8 without converting, ie6 don't convert at all.




  • responseXML lost across windows?
    2005-06-09 10:42:10 JJG [Reply]

    I am trying to use XMLHttpRequest in a client-side firefox plugin. I want to open a sign-in dialog, and then use the user's input to send a GET request to the server for authorization.


    Unfortunately, the XMLHttpRequest's responseXML always comes in null if I let the dialog close before the server response is received. The call is being made on a global object which is created in the main plugin overlay, to which the request is attached. The actual request object is maintained (I verified that it was the same by setting the value of a property when the request is created and checking it in my request change listener), but the responseXML is nulled out. If I put in an alert that prevents the dialog from closing before the response is received, all is well.


    I tried the theadsafe version posted here, but no dice. My only guess is that the responseXML object is temporarily placed on the current window during processing, and it is getting lost when my dialog gets destroyed. Any insight, suggestions for workarounds, or examples of similar code would be appreciated.

  • non-active x implementation for IE?
    2005-06-09 01:27:13 akrinsky [Reply]

    What if your client doesn't want to enable ActiveX scripting?


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


    Has anyone implemented a pure DHTML/javascript version of this library for IE?

  • A threadsafe implementation for XMLHTTPRequest
    2005-05-27 12:48:37 brockweaver [Reply]

    One of the things that pops out at most developers is the thread safety issues of the example code. While the example works fine for testing, the very nature of programming web apps in this manner means it is *extremely* likely multiple requests will be issued concurrently.


    The following is thread-safe code to do just that. I've used the Ajax moniker, as that is what a lot of people call this technique. Personally, I don't care if they call it furrycatofdeath, as long as it works. :)


    Essentially, this code uses a technique called inner functions. These are useful in this situation because the variables declared on the outer function are available to the inner function -- and do not fall out of scope until *after* the inner function has been executed. Since the request and callback variables (which contain function pointers to the good stuff) are declared locally, each call to the ajaxSend function creates a new copy, so the previous one is left intact.


    A great discussion and analysis of this methodology (and other similar methodologies) is described in detail at
    http://jibbering.com/faq/faq_notes/closures.html


    Mind you, I found this via a Google search and I am completely unrelated with its content, so that url may change without my knowledge. Hopefully it will not, as it is a very clear and well written article!


    At any rate, the source follows. If you have issues with it, please let me know, as I haven't had a chance to test many platforms yet. Thank you!


    // threadsafe asynchronous XMLHTTPRequest code
    function ajaxSend(url, callback){


    // we use a javascript feature here called "inner functions"
    // using these means the local variables retain their values after the outer function
    // has returned. this is useful for thread safety, so
    // reassigning the onreadystatechange function doesn't stomp over earlier requests.


    function ajaxBindCallback(){
    if (ajaxRequest.readyState == 4) {
    if (ajaxRequest.status == 200) {
    if (ajaxCallback){
    ajaxCallback(ajaxRequest.responseXML);
    } else {
    alert('no callback defined');
    }
    } else {
    alert("There was a problem retrieving the xml data:\n" + ajaxRequest.status + ":\t" + ajaxRequest.statusText + "\n" + ajaxRequest.responseText);
    }
    }
    }


    // use a local variable to hold our request and callback until the inner function is called...
    var ajaxRequest = null;
    var ajaxCallback = callback;


    // bind our callback then hit the server...
    if (window.XMLHttpRequest) {
    // moz et al
    ajaxRequest = new XMLHttpRequest();
    ajaxRequest.onreadystatechange = ajaxBindCallback;
    ajaxRequest.open("GET", url, true);
    ajaxRequest.send(null);
    } else if (window.ActiveXObject) {
    // ie
    ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
    if (ajaxRequest) {
    ajaxRequest.onreadystatechange = ajaxBindCallback;
    ajaxRequest.open("GET", url, true);
    ajaxRequest.send();
    }
    }


    }





  • Great introduction, now what about refreshing lists?
    2005-05-11 08:10:09 acidbox [Reply]

    I found this article to be a great introduction to how the whole XML/JS interaction works. My question is, if I used this to insert a record into a database using PHP/MySQL, how would I go about refreshing a list of records with the newly inserted data appended to the list?

  • Knowledge Base Application
    2005-05-06 08:07:25 Julian Turner [Reply]

    I have produced a simple example of AJAX use for a knowledge base.


    www.baconbutty.com


    In terms of history, my web page maintains the history, although it loses it when the browser is closed.

  • Chess GUI
    2005-04-24 04:22:46 JOlsen [Reply]

    Nice tutorial.


    I implemented this chess GUI after reading your article.


    http://www.JesperOlsen.Net/PChess/


    Cheers
    Jesper

  • Data the other way round
    2005-04-21 11:35:17 nGear [Reply]

    This is data pulled by the client from the server.
    Is there a way to push data from the server to the client?
    (Without the client polling the server..)
    i.e. update the client without any requests from the client itself.

  • Concerns
    2005-04-03 07:00:05 sunnyO5 [Reply]

    I am excited about the possible applications of XMLHttpRequest Object but I have some concerns:


    1) Using XMLHttpRequest Object can save a lot of bandwidth but does it support caching of webpages in the browser? Webpages using XMLHttpRequest Object seem to loose the browser's history features; you can't use the Go back and forward buttons. Like in the Apple's example (http://developer.apple.com/internet/webcontent/XMLHttpRequestExample/example.html), one has to make the choices again to view the information. So can't view the information offline.


    2) In the Google Suggest example, for each key press a request is sent to the server. So if you have 50 users typing an average of 10 letters, you have more than 500 requests sent to the server. Is this a huge concern for developing applications with this sort of feature (like dynamic function lookup on php.net)?


    Nevertheless, XMLHttpRequest Object promises a better interaction with the user.
    Thanks.

  • Problem
    2005-03-24 14:35:49 Goonie [Reply]

    I'd like to load an XML/HTML fragment from the server and replace a node in the document by that fragment. That way, I could periodically refresh a specific region of the page.


    Here is what I'm doing in the readyStateChange handler:


    e = document.getElementById('fragment');
    e.parentNode.replaceChild(req.responseXML.firstChild, e);


    Unfortunately, an XML fragment that is fetched via XMLHttpRequest is not accepted as valid HTML by Gecko/Firefox: It only shows up as text-only, without any formatting. What's worse, getElementById() does not locate my fragment after it has been replaced once.


    Is it possible to convert an XML node to an HTML element/node before insertion into the DOM?


    Are there any good books on the matter that go well beyond this article?


    Regards,


    Andreas


  • I realize that I'm on XML.com, but....
    2005-03-23 07:09:49 mdchaney [Reply]

    Please don't use XML for such a simple request. Actually, I'm not convinced that XML is the best method for sending any data to JavaScript. I do a lot of work with XMLHTTPRequest, and I simply use the standard JavaScript object literal and array literal notations.


    Now, I know the above is a simple demonstration, but for a simple flag response you need to return only a 1 or 0. To keep with the example, though, you can return a JS object:


    { method: 'checkName', result: 1 };


    Then, the function is simplified:
    function processReqChange()
    {
    // only if req shows "complete"
    if (req.readyState == 4) {
    // only if "OK"
    if (req.status == 200) {
    // ...processing statements go here...


    --> eval('response = '+req.responseText);


    eval(response.method + '(' + response.result + ');');
    } else {
    alert("There was a problem retrieving the XML data:\n" + req.statusText);
    }
    }
    }


    Obviously, for such a simple example there's little gain. But imagine trying to traverse an entire DOM tree for a large document. Using literals, you can create native JS objects and use the much simpler constructs such as "for/in" to manipulate the data. You can also directly address known data, as shown above.


    Make the choice between this:


    response.method


    or this:


    response.getElementsByTagName('method')[0].firstChild.data;


    It also probably goes without saying, but the backend code is also greatly simplified by not having to create an XML document.

  • Working Example
    2005-03-14 03:28:27 Julian Turner [Reply]

    If anyone is interested, I have used the XMLHTTP Request as the back-bone to my website www.baconbutty.com.


    The database/index for the web site is a series of linked XML flat files currently, which I access using a simple RegExp/String based XML reader I have written, to save server overheads in parsing the XML database.

  • The correct code
    2005-03-02 12:29:03 xmL [Reply]

    You can find it here
    http://www.xmlhttprequest.net/forum/viewtopic.php?p=9#9


    Fixed some bugs for this good example.


    xmL

  • Re: Example
    2005-02-24 14:16:03 rk9728 [Reply]

    Does anyone have a working example that we could see online? It's a bit frustrating to see these great articles but not the actual *demo* itself :0

  • Good Article!
    2005-02-19 18:08:08 DanielBThurman [Reply]

    I have pretty much followed your article and converted the code presented to use ASP code and it works well. I do have one annoying issue.


    When the name is typed and the onblur event is fired, a popup dialog on IE that warns the user with this message: 'This page is accessing information that is not under its control. This poses a security risk. Do you want to continue?'


    Is there some way to block this message or does all browsers have this sort of thing built in?


    The other question is, what about passing passwords - NON-SECURELY - using this code? I assume that this is easily handled via https:// connection, bypassing the need to do client-side encryption.


    Other than that -- server-side processing is done without a round-trip page refresh and there is no noticeable client-side renderering and the response appears quickly, which is impressive.


    Dan Thurman

  • XMLHTTP is Good but Needs WS-Security
    2005-02-18 13:40:55 ErikJ [Reply]

    We use XMLHTTPRequest to send/receive SOAP in a couple of products we ship. Two other useful things we leverage: The Windows version knows how to handle NT Challenge/Response, so you can call sites running under Windows Integrated Security transparently. It also supports HTTP 1.1 compression, so you can GZIP your payload on the server (SOAP usually compresses well).


    But what we really need is the ability to sign/encrpyt messages using WS-Security standards. In Microsoft's case, version 5 of the MSXML parser kit (which contains XMLHTTPRequest) has a few features, but you only get that version with Office 2003. Version 6 is coming, but I've heard Microsoft may have to pull out the signing/encrypting functions at least for now.


    I haven't reviewed Mozilla/Safari support for WS-Security yet, but having that functionality in genreal would be quite helpful.




  • micro applet can work as well
    2005-02-16 09:59:42 jseller [Reply]

    Reminds me of a project in which we ended up using a very small applet working in the background to co-ordinate between ecmascript in the browser (using com.netscape.javascript.*) and interacting with the server through a persistent connection (using java.net.*) No need from browser refresh for small updates, it handled the UI event handling and was less than 10kb. This was around 1998 so it's kind of fuzzy, but I remember it worked well.
    I definitely remember that it seemed sort of weird at the time getting the Netscape javascript classes to work in Internet Explorer on the Mac os9.

  • DOM 3 & simplification
    2005-02-14 05:45:48 JimDabell [Reply]

    Er, DOM 3 Load and Save isn't a "proposed specification". It was released as a Recommendation in April 2004 and has been implemented by multiple browsers already. It's never going to be as well-supported as XMLHttpRequest because, hey, Internet Explorer. that doesn't mean it isn't a stable, deployed specification though.


    You can simplify the instantiation of the XMLHttpRequest object by simply including a little bit of generic Javascript before you use the native object method:


    if (typeof XMLHttpRequest != "object") {
    function XMLHttpRequest() {
    return new ActiveXObject("Microsoft.XMLHTTP");
    }
    }


    That way you can simply call new XMLHttpRequest() for Internet Explorer in the same way that you do for all the other browsers.


  • Coldfusion Server Script
    2005-02-11 08:05:06 makalu [Reply]

    I re-wrote the server script in coldfusion to see if I could get it working on my cfmx box, here's the code from that, if anyone is interested...


    <cfcontent type="text/xml" reset="yes">
    <cfscript>
    function nameInUse(q)
    {
    if (isdefined("q")){
    switch(lcase(q))
    {
    case 'drew': {
    return '1';
    break;
    }
    case 'fred': {
    return '1';
    break;
    }
    default:
    return '0';
    }
    }else
    return '0';
    }
    </cfscript>
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response>
    <method>checkName</method>
    <cfoutput><result>#nameInUse(url.q)#</result></cfoutput>
    </response>

  • XSL
    2005-02-11 02:13:32 redben [Reply]

    I have been working in this style (XML Javascript XSL) for about 2 years now but only with ie. Mozilla had little xml support at that time. I know that now it fully does, and i'm happy for that :) since it will unlock me from developping for ms ie.
    But there is one thing a still don't know how is mozilla's XSL implementation ? somebody ever tried it ? i'd really like to go crossbrowser again.

  • Very nice article
    2005-02-10 18:47:27 robhudson [Reply]

    I'd like to see more like this as I think this is a technology that's taking off. Maybe more complicated XML requests and responses, how to send data with POST, etc.

  • Don't forget www in the URL
    2005-02-10 09:29:16 ideawire_bb [Reply]

    Good article, easy to follow.


    For some reason, in all browsers I tested (IE 6 Win, Safari Mac, Firefox Mac / Win) it only works if you utilize the root url, ie:


    http://www.domain.com/form.html


    The script simply won't work if you try and access it this way:


    http://domain.com/form.html


    Hope this saves someone the time and frustration I experienced.

  • Nice, but one small error
    2005-02-09 23:53:32 dzac [Reply]

    I tried the example, and at least in Safari and FireFox 1.0 on the Mac, the function 'checkName' should read:


    ...
    if (response == 1)
    ...


    rather than:


    if (response == '1')


    (note the quotes).


    With that change everything worked as advertised.