track7
sign in
sign in securely with your account from one of these sites:
note:  this is only for users who have already set up a password.

getting started with ajax

intermediate ajax, js, php 2168 misterhaan

ajax can be a great way to enhance the user experience of a website. this guide discusses the basics of ajax and introduces useful javascript functions and properties involved in implementing ajax features from scratch. basic dom-based javascript knowledge is assumed. php is used for the discussion of the server-side support.

ajax concepts

ajax is an acronym for asynchronous javascript and xml. the important part of this name is asyncronous javascript — send a request to a web server using javascript code, and wait in the background for the result to load. once the result has loaded, it’s available to javascript to read and usually either update the current page, display an alert, or take some other action.

the “and xml” part of the name refers to the format the response data uses. in practice xml is only one of the options, which happens to have extra support built in by automatically loading xml into an object for manipulation. depending on the specific use however it may be more appropriate to send html, tab-separated values, or just a plain-text list of options separated by line breaks.

using ajax can save time and enhance the experience of a web site by avoiding a full page load for small tasks. if most of the page should stay the same but some additional information or analysis is required from the server, that’s probably a good candidate for ajax. some examples are validating input without leaving the form, suggesting common values for a text field, or saving a forum post in the database and then adding it to the page without reloading.

if at all possible, make the feature at least minimally usable first without any javascript, then come back and enhance it with ajax. this way users who are able to run ajax get the fully enhanced experience, but those who are unable can still get done what they need to do, even if it’s not quite as convenient.

an ajax feature is implemented in three phases: sending the request, generating the response, and acting on that response. the first and last phases are handled by the javascript code from a single page, while the second phase is handled on the web server while the javascript waits. this guide goes through the phases in chronological order, which means we jump from javascript to php and then back.

sending the request

practically everything happens through an XMLHttpRequest object. the first step is creating one. most browsers support new XMLHttpRequest() but older versions of internet explorer (technically msxml libraries used by internet explorer) required creating an ActiveXObject. to handle both the current method and two older msxml methods, as well as browsers that don’t support ajax at all, i use a function to get the best available XMLHttpRequest object, or null if ajax is unavailable:

/**
 * Get an XMLHttpRequest object from the best available of three options.
 * @return XMLHttpRequest object.
 */
function ajaxRequestObject() {
  var req = null;
  try {
    // modern browsers and internet explorer 7+
    req = new XMLHttpRequest();
  } catch(e) {
    try {
      // internet explorer 6
      req = new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
      try {
        // older internet explorer
        req = new ActiveXObject("Microsoft.XMLHTTP");
      } catch(e) {}  // couldn't get an http request object
    }
  }
  return req;
}

the function starts by initializing the request object req to null, then tries to create it using new XMLHttpRequest(), and if that fails tries to create an Msxml2.XMLHTTP ActiveXObject, or Microsoft.XMLHTTP if that fails. finally it returns the request object, which is still null if all three failed.

once the object is created, you need to set the function to run when the request is finished and define the request before sending the request. defining the request needs to be done before sending the request so that there’s something to send, but setting the function will actually work sometimes if done after sending the request. since an ajax request is asynchronous, if the connection to the server is fast enough and the request is small enough, it could finish before the function is actually set. i have actually seen this happen where the function just doesn’t get called.

setting the function to run when the request finishes requires a little extra work to make sure it only runs when the request is actually finished, since the event is ReadyStateChange and could be triggered when the ready state is something other than finished. also i often find it useful to send some additional data to the function (for example, the html element it will need to modify). for this reason i wrap everything up in a function that sets the function to call and submits the request. here’s the function i use that does an http get request:

/**
 * Submit an asynchronous HTTP request using the GET method.
 * @param url URL to request.  May contain querystring parameters, and usually will.
 * @param finished Function to call when the request has completed.  Should accept two arguments:  the XMLHttpRequest object with the results, and the args parameter passed to this function.
 * @param args Any argument(s) the completion function may need.  Use an array to pass multiple values.
 * @return The XMLHttpRequest object on success, or false on failure.
 */
function getAsync(url, finished, args) {
  var req = ajaxRequestObject();
  if(req == null) {
    alert("your browser supports javascript but not ajax.  please update your browser or try again with javascript off.");
    return false;
  }
  req.onreadystatechange = function() {
    if(req.readyState == 4)
      finished(req, args);
  }
  req.open("GET", url, true);
  req.send(null);
  return req;
}

the function starts out by creating a request object using the function given above. it then displays an error message if it wasn’t able to create a request object. next it creates a function which gets set as the handler for the readystatechange event. the function checks that the request’s readyState property is 4, which means completed (note some people also verify that the status property is 200, which is the http code for success) before calling the function that was passed as the second argument. both the request object and any data passed in the third argument are passed to the function. now that the request object is ready to call a function on completion, define the request using the open method. this function always uses http get as the method, so that’s the first parameter.

the second parameter is the url exactly as it was passed to the function. the url is basically anything you could put as the href property for a link — if it’s for a script in the same directory as the current page you don’t need a path at all and can just use script.php?value1=data1&value2=data2. if it’s in a different directory i recommend using the path from the server root, like /dir/subdir/script.php?value1=data1&value2=data2. finally the third parameter is true to indicate that the request should run in the background.

to finish up the function the request is sent using the send method. null is passed here because it’s a get request. if using post, this would instead be a string of the post data, formatted like value1=data1&value2=data2. next the request object is returned. since objects evaluate to true, it can be used in an if statement to determine whether the request was created. also the request object has an abort method which can be used to stop waiting for the request to complete — if there’s a possibility of needing to abort then a reference to the request object needs to be kept.

sending a post request isn’t much different. here’s the function i use for that:

/**
 * Submit an asynchronous HTTP request using the POST method.
 * @param url URL to POST request.  May contain querystring parameters.
 * @param finished Function to call when the request has completed.  Should accept two arguments:  the XMLHttpRequest object with the results, and the args parameter passed to this function.
 * @param args Any argument(s) the completion function may need.  Use an array to pass multiple values.
 * @param params POST data for the request.  May be a string formatted var1=data1&var2=data2 or an array of strings formatted var=data.
 * @return The XMLHttpRequest object on success, or false on failure.
 */
function postAsync(url, finished, args, params) {
  var req = ajaxRequestObject();
  if(req == null) {
    alert("your browser supports javascript but not ajax.  please update your browser or try again with javascript off.");
    return false;
  }
  req.onreadystatechange = function() {
    if(req.readyState == 4)
      finished(req, args);
  }
  req.open("POST", url, true);
  var data = params instanceof Array ? params.join("&") : params;
  req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  req.send(data);
  return req;
}

the first difference is there’s now params as the new fourth parameter. this is for the post data to send with the request. the open method is now called with POST instead of GET, since this function sends requests via post. next params is assembled into data. params can either be an array where each value is formatted valueN=dataN, or a string formatted value1=data1&value2=data2. the instanceof Array figures out if an array was passed (and then joins the array values with & in between), or a string (which is used as is). a new method setRequestHeader on the request object is used to set a header necessary for post requests. this explains what format the data is in. the final diffirence is now there is data passed to the send method.

generating the response

ajax requests should usually be sent to the same server that served the page the ajax javascript is running on, which means the ajax response will also come from that same server. the simplest case is responding with a static file (probably an xml or txt file), in which case all that needs to be done on the server is to make sure the file is in place. more often though it will be necessary to run a script on the server to process the data sent with the request and respond appropriately.

a consideration with using php (or any other server-side language) is that the server is probably set to send headers saying php output is html. with ajax you may sometimes be using html, but often xml or plain text is more appropriate. for those cases you should send the appropriate header for the format of the response. in php, this is done with the header function. other server-side languages have similar functions.

the header needed is Content-Type. for xml you want the value set to text/xml, and for plain text text/plain. it’s also a good idea to include the character set since plain text doesn’t allow for that within the content (xml does, but the header is read before the content so is the best place to put character set). here are a couple lines of php code you can choose from. note that headers need to be sent before any content — most server-side languages will give you an error if you’ve already put out or <?xml... and then try to set a header.

<?
  // choose the correct line for your case -- only use one
  header('Content-Type: text/xml; charset=utf-8');
  header('Content-Type: text/plain; charset=utf-8');
?>

after setting the content-type, the script needs to actually generate the xml / plain-text / etc. content. this follows the same rules as generating html, where you can use echo or print to write out values, or jump out of php with ?> to write out a large block.

dynamic responses can either come from existing scripts that generate full pages or dedicated scripts that only respond to ajax requests. keep in mind that either way the script needs to be accessible to a browser, so it’s possible someone could see the contents of the response in their browser. i find it cleaner to not have php scripts that don’t generate normal pages, so when i need to code a response to an ajax request i find an existing page that deals with the same data and add it there. often to indicate that i need an xml response for ajax i will start the querystring with ?return=xml. other times i don’t need that since i’m already sending other data that i only send with ajax requests. you may find it cleaner to have separate scripts that only respond to ajax requests, maybe under an /ajax/ directory on your site — it’s a personal preference as i don’t see a specific advantage to either method.

since the response needs to be accessible to the browser, you can test that you’re generating the correct response by requesting the ajax script with the correct querystring directly from the browser — just enter the url in the browser address bar. if you sent the correct content-type, the browser should display the result correctly. while this works well for get requests, post requests are more difficult as there’s not a straightforward way of sending the post data manually.

taking action

the final piece to an ajax feature is to do something based on the response. this is done in the javascript function called in the readystatechange event handler. two more properties of the XMLHttpRequest object are useful at this point: responseText and responseXml. generally one or the other fits — if the response is in xml you use responseXml and if it’s not you use responseText. one of these is always needed, which is why it’s important to ensure the function handling the response has access to the XMLHttpRequest object.

xml responses follow the document object model (dom), which means the generic dom functions in javascript that can be used to manipulate html can also be used to read the response. keep in mind that you cannot take a node from the xml and add it to the html page directly since nodes are not allowed to cross documents. instead read the data from the xml and create new elements in the html page to hold the data. the responseXml.documentElement property is the root node of the xml. you can navigate to other nodes using firstChild, nextSibling, and other related properties. to get data out of an attribute such as <element value="data">, you need to access the element’s attributes property, use the getNamedItem function to get the attribute, then the value property to access the attribute’s value: node.attributes.getNamedItem("value").value. to get data stored directly in an element, you need to first access the element’s firstChild property to get to the text node inside, then use the nodeValue property for the actual data.

text responses are a string, which you will normally need to split up on your own. javascript string functions such as split come in handy here. if the text has multiple values each on their own line, you can easily turn the string into an array by using var values = ajaxResponse.responseText.split("\n"). for something like tab separated values you would use split again with "\t" on each line to turn each line into an array of values.

if the response is an html segment to add to the page, it’s usually easiest to create a div element and set its innerHTML property to the html segment (from responseText), then add the div to the html page. treating the html response as xml and recreating all nodes in the html page is possible but requires a lot of javascript code and is also slower.

sometimes the appropriate response is to pop up a message using alert (like when the request failed on the server), or something else that doesn’t modify the current page. for example, track7 has an ajax login script which will show an alert if the username and password entered are incorrect, or reload the page if the user was successfully logged in.

now that you’ve seen the basics of ajax, you may want to have a look at the other ajax guides on track7 for some ideas and specific examples!

how was it?

comments

{{error}}

there are no comments on this guide so far. you could be the first!

{{comment.name}}
posted