SNTT on Ajax - Flip your Factory Upside Down
Category None
When developing Ajax applications, you are making XMLHttpRequest object calls. They look something like this:
function initXMLHttpRequest(){
var objHTTP = null;
if(window.ActiveXObject){ //IE
if(g_XMLHttpRequest_ActiveX){
objHTTP = new ActiveXObject(g_XMLHttpRequest_ActiveX);
}else{
var xmlhttp = new Array(
'Msxml2.XMLHTTP.7.0',
'Msxml2.XMLHTTP.6.0',
'Msxml2.XMLHTTP.5.0',
'Msxml2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP');
for(var i = 0; i < xmlhttp.length; i++){
try{
objHTTP = new ActiveXObject(xmlhttp[i]);
if(objHTTP != null){
g_XMLHttpRequest_ActiveX = xmlhttp[i];
break;
}
}catch(e){}
}
}
}else{ //Mozilla
try{
objHTTP = new XMLHttpRequest();
}catch(e){}
}
return objHTTP;
}
This is all fine and good. Better in fact than you might think, as it is using the Factory pattern for creating the object. What's a factory pattern? Well basically, it's where you have a function to create the object, you call the function once to see if the object exists, then re-use the object the next time. It's a concept introduced in Design Patterns (1995) and often used with Java and C, though there you have the concepts of interfaces and implementations that you don't have in a dynamic language like JavaScript. If you're making a new XMLHTTPRequest object every time you want to make an Ajax call on a form or page, consider this method as a time-saver and performance booster.
When developing Ajax applications, you are making XMLHttpRequest object calls. They look something like this:
function initXMLHttpRequest(){
var objHTTP = null;
if(window.ActiveXObject){ //IE
if(g_XMLHttpRequest_ActiveX){
objHTTP = new ActiveXObject(g_XMLHttpRequest_ActiveX);
}else{
var xmlhttp = new Array(
'Msxml2.XMLHTTP.7.0',
'Msxml2.XMLHTTP.6.0',
'Msxml2.XMLHTTP.5.0',
'Msxml2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP');
for(var i = 0; i < xmlhttp.length; i++){
try{
objHTTP = new ActiveXObject(xmlhttp[i]);
if(objHTTP != null){
g_XMLHttpRequest_ActiveX = xmlhttp[i];
break;
}
}catch(e){}
}
}
}else{ //Mozilla
try{
objHTTP = new XMLHttpRequest();
}catch(e){}
}
return objHTTP;
}
This is all fine and good. Better in fact than you might think, as it is using the Factory pattern for creating the object. What's a factory pattern? Well basically, it's where you have a function to create the object, you call the function once to see if the object exists, then re-use the object the next time. It's a concept introduced in Design Patterns (1995) and often used with Java and C, though there you have the concepts of interfaces and implementations that you don't have in a dynamic language like JavaScript. If you're making a new XMLHTTPRequest object every time you want to make an Ajax call on a form or page, consider this method as a time-saver and performance booster.
You'd call the function as many times as you need with code like this:
function getCalendarEntries(calendarTitle,dbFileName,viewName,dateToGet){
var objHTTP = initXMLHttpRequest();
var sURL = '/' + dbFileName + '/' + viewName + '?ReadViewEntries&Date=' + dateToGet + '&Grid=4&Count=1000';
try{
objHTTP.onreadystatechange = function() {
if(objHTTP.readyState == 4) {
if(typeof objHTTP.status == 'undefined' || objHTTP.status == 200 || objHTTP.status == 304){
createCalendarEnriesArray(objHTTP.responseXML,calendarTitle,dbFileName,viewName);
}else{
//var oError = new Object();
//oError.description = objHTTP.statusText;
//throw(oError);
}
}
};
objHTTP.open("POST", sURL, true);
objHTTP.send(null);
}catch(e){
if(typeof alertError == "function"){
alertError(e);
}
}
}
Now this tip isn't really about Ajax syntax or how to make a call, but rather a note on what's wrong with the factory code above. It wasn't really wrong until a few weeks ago...
See that line near the end "objHTTP = new XMLHttpRequest();"? That was the call for Firefox, because it didn't need the ActiveX crud. We could call it second, because most users would have IE6. And now with IE7, this also works. But so does ActiveX, and if we keep the code in this order, it'll load an ActiveX object for IE7 users instead of going with the "native" object. So if you are making XMLHTTPRequest object calls for Ajax code in Domino (or anywhere else), you want to flip the factory upside-down from now on:
function initXMLHttpRequest(){
var objHTTP = null;
if (window.XMLHttpRequest) { //IE7 and FF
try{
objHTTP = new XMLHttpRequest();
}catch(e){}
}else if(window.ActiveXObject){ //IE6 and below
if(g_XMLHttpRequest_ActiveX){
objHTTP = new ActiveXObject(g_XMLHttpRequest_ActiveX);
}else{
var xmlhttp = new Array(
'Msxml2.XMLHTTP.7.0',
'Msxml2.XMLHTTP.6.0',
'Msxml2.XMLHTTP.5.0',
'Msxml2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP');
for(var i = 0; i < xmlhttp.length; i++){
try{
objHTTP = new ActiveXObject(xmlhttp[i]);
if(objHTTP != null){
g_XMLHttpRequest_ActiveX = xmlhttp[i];
break;
}
}catch(e){}
}
}
}
return objHTTP;
}
Astute JavaScripters among you will probably notice that I could achieve the same thing with a change in the first IF statement, changing it to:
if(window.ActiveXObject&& !window.XMLHttpRequest){
You'd be right of course but that's just not as clean to me. There's no need to test for a condition, see that it's true, then concatenate another condition that is false in order to arrive at false.
So what did we accomplish here? By flipping the order of the ActiveX and native XMLHttpRequest object calls, we've optimized the code for newer browsers, improving performance for them while sacrificing nothing for older ones.

Comments
Posted by Ben Langhinrichs At 04:01:38 PM On 11/09/2006 | - Website - |
http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
Posted by Johan At 06:02:58 AM On 11/13/2006 | - Website - |
confusedgurl
Posted by lil At 02:37:32 PM On 11/25/2006 | - Website - |