This is a class I wrote as a browser-agnostic Ajax requestor. Note that it is not proper AJAX because it does not REQUIRE xml as either input or output.
Usage:
ajax1 = new ajaxRequestor()
ajax1.url = '/handlingPage.php';
ajax1.postParam('aPostParameter', 'theValue');
ajax1.onSuccess = handleAjax;
ajax1.execute();
function handleAjax(sender)
{
alert(sender.lastResponse);
}
Essentially, you create one, give it a URL it will be going to, optionally add parameters in the POST content of the request, set a function to handle the response, and execute it. Note that it is in the postParameters where you would place XML, or put many post parameters or whatever. The handler is sent a single parameter - which I most often call "sender" - access the lastResponse property to see what you got back. It can be HTML, XML, anything at all - it's up to you.
I often do stuff like this:
ajax1.postParam('request', 'savestuff');
ajax1.postParam('firstname', document.getElementById('fname').value);
and such... where I push values directly from the HTML document into the requestor without the structure or weight of XML at all. I often just ship back straight up HTML that is already formatted and ready to go as well:
function handleAjax(sender) { document.getElementById('answerArea').innerHTML = sender.lastResponse; }
The request at the server looks identical to a normal page request - you don't need to do anything wierd or different at all. Here is the code for my class:
// ----------------------------------------------------------- //
// ajaxRequestor //
// ----------------------------------------------------------- //
function ajaxRequestor() { this.clearAll(); }
ajaxRequestor.prototype.__defaultError = function(sender)
{
var tempStr = "ajaxRequestor Error:\n" +
"status: " + this.requestor.status + "\n" +
"headers: " + this.requestor.getAllResponseHeaders();
alert(tempStr);
}
ajaxRequestor.prototype.__defaultSuccess = function(sender)
{
alert("ajaxRequestor successfully returned from a request - but there is no handler assigned to receive it");
}
ajaxRequestor.prototype.__decodeString = function(inputStr)
{
var decoded = unescape(inputStr);
decoded = decoded.replace(/\%2F/g, "/");
decoded = decoded.replace(/\%3F/g, "?");
decoded = decoded.replace(/\%3D/g, "=");
decoded = decoded.replace(/\%26/g, "&");
decoded = decoded.replace(/\%40/g, "@");
return decoded;
}
ajaxRequestor.prototype.__encodeString = function(inputStr)
{
var encoded = escape(inputStr);
encoded = encoded.replace(/\//g,"%2F");
encoded = encoded.replace(/\?/g,"%3F");
encoded = encoded.replace(/=/g,"%3D");
encoded = encoded.replace(/&/g,"%26");
encoded = encoded.replace(/@/g,"%40");
return encoded;
}
ajaxRequestor.prototype.__getParams = function()
{
if (this.getNames.length == 0) { return ""; }
var out = (this.url.indexOf('?') == -1) ? '?' : '&';
for (var i=0; i<this.getNames.length; i++)
{
out += this.getNames[i] + '=' + this.getValues[i];
if (i < (this.getNames.length - 1)) { out += '&'; }
}
return out;
}
ajaxRequestor.prototype.__getRequestor = function()
{
if ((this.requestor != null) && (!this.reqIsIE)) { return true; }
try {
this.requestor = new XMLHttpRequest();
this.reqIsIE = false;
return; true;
} catch(e) {}
try {
this.requestor = new ActiveXObject("Msxml2.XMLHTTP.6.0");
this.reqIsIE = true;
return; true;
} catch(e) {}
try {
this.requestor = new ActiveXObject("Msxml2.XMLHTTP.3.0");
this.reqIsIE = true;
return; true;
} catch(e) {}
try {
this.requestor = new ActiveXObject("Msxml2.XMLHTTP");
this.reqIsIE = true;
return; true;
} catch(e) {}
try {
this.requestor = new ActiveXObject("Microsoft.XMLHTTP");
this.reqIsIE = true;
return; true;
} catch(e) {}
alert('ajaxRequestor Fatal Error: Cannot instantiate an XMLHTTP Object');
}
ajaxRequestor.prototype.__xmitLog = function(theMsg)
{
var bodyArr = document.getElementsByTagName('body');
var theBody = bodyArr[0];
theBody.appendChild(document.createTextNode(theMsg));
theBody.appendChild(document.createElement('br'));
}
ajaxRequestor.prototype.__onRTS = function()
{
if ((this.requestor.readyState >= 2) && (this.timeoutHandle))
{
clearTimeout(this.timeoutHandle);
this.timeoutHandle = false;
}
if (this.requestor.readyState == 4)
{
if (this.masterStatus) { this.masterStatus.handleChange(false); }
if ((this.requestor.status==200) || (this.requestor.status==0))
{
this.lastResponse = this.__decodeString(this.requestor.responseText);
if (!this.lastResponse)
{
return false;
}
if (this.xmlHandler)
{
this.xmlHandler.importXML(this.lastResponse);
}
this.onSuccess(this);
} else {
switch(this.requestor.status)
{
case 12029:
case 12030:
case 12031:
case 12152:
case 12159:
// OK: It's the IE SSL bug. Create a tiemout to call <me> again...
var loader = this;
setTimeout( function() { loader.execute.call(loader); }, 10);
break;
default:
this.onError(this);
}
}
this.busy = false;
}
}
ajaxRequestor.prototype.__postParams = function()
{
var out = "";
var varNames = '';
for (var i=0; i<this.postNames.length; i++)
{
if (i > 0) { varNames += '|'; }
varNames += this.postNames[i];
if (i > 0) { out += '&'; }
out += this.postNames[i] + '=' + this.__encodeString(this.postValues[i]);
}
if (out) { out += '&' + 'ajax_var_names=' + varNames; }
return out;
}
ajaxRequestor.prototype.abort = function()
{
if (this.busy)
{
// clear timeout as well
this.requestor.abort();
clearTimeout(this.timeoutHandle);
this.timeoutHandle = false;
this.busy = false;
}
}
ajaxRequestor.prototype.clear = function()
{
this.methodPost = true;
this.__transStatus = 0;
this.__transBusy = false;
this.lastResponse = new String();
this.selfReference = null;
this.newRequest();
this.timeoutHandle = false;
this.timeoutMS = 8000;
}
ajaxRequestor.prototype.clearAll = function()
{
this.xmlHandler = null;
this.masterStatus = null;
this.onUnrecognized = new String();
this.onError = this.__defaultError;
this.onSuccess = this.__defaultSuccess;
this.clear();
}
ajaxRequestor.prototype.execute = function(timeoutVal)
{
if (this.busy)
{
// clear timeout as well
this.requestor.abort();
this.busy = false;
}
var thisTimeoutVal = this.timeoutMS;
if (timeoutVal != undefined) { thisTimeoutVal = timeoutVal; }
this.__getRequestor();
if (!this.requestor) {
alert("You cannot dispatch a request on this machine (no viable XMLHTTPRequestor)");
return "";
}
if (!this.url) {
alert("You must supply a URL to ajaxRequestor to process a request");
return "";
}
this.busy = true;
var httpMethod = (this.methodPost) ? 'POST' : 'GET';
var theURL = this.url;
theURL += this.__getParams();
this.lastRequest = theURL;
var loader = this;
this.requestor.onreadystatechange = function() { loader.__onRTS.call(loader); }
if (this.masterStatus) { this.masterStatus.handleChange(true); }
// Set a callback to <me> in case the request takes to long...
this.timeoutHandle = setTimeout( function() { loader.__handleTimeout.call(loader); }, this.timeoutMS);
this.requestor.open('POST', theURL, true);
this.requestor.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
this.requestor.send(this.__postParams());
}
ajaxRequestor.prototype.__handleAbort = function()
{
if (this.masterStatus) { this.masterStatus.handleChange(false); }
this.requestor.onreadystatechange = null;
this.requestor.abort();
}
ajaxRequestor.prototype.__handleTimeout = function()
{
this.__handleAbort();
var loader = this;
setTimeout(function() { loader.execute.call(loader); }, 100);
}
ajaxRequestor.prototype.getParam = function(key, value)
{
var ptr = this.getNames.length;
for (var i=0; i<this.getNames.length; i++)
{
if (this.getNames[i] == key) { ptr = i; }
}
this.getNames[ptr] = key;
this.getValues[ptr] = value;
}
ajaxRequestor.prototype.method = function(doPost)
{
this.methodPost = (doPost);
}
ajaxRequestor.prototype.newRequest = function()
{
this.getNames = new Array();
this.getValues = new Array();
this.postNames = new Array();
this.postValues = new Array();
this.url = '';
}
ajaxRequestor.prototype.postParam = function(key, value)
{
var ptr = this.postNames.length;
for (var i=0; i<this.postNames.length; i++)
{
if (this.postNames[i] == key) { ptr = i; }
}
this.postNames[ptr] = key;
this.postValues[ptr] = value;
}