« Great presentation on rich Internet applications | Main| New bloggers in our midst »

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.  


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

Gravatar Image1 - Cool, good to know. I'll go fiddle with our Help db (which uses these calls) right now. Thanks!

Gravatar Image2 - Some clarification about the different versions of MSXML in Internet Explorer that is worth knowing about in relation to this post...

http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx

Gravatar Image3 - what does the upside down star with the circles on the tips mean ?????


confusedgurl

Backstage Pass to Ask

Be With the Band

Follow me on Twitter!


Opt in to receive Rob's semi-regular newsletter about Quickr, Sametime, Free Stuff and Conferences. Just enter your email address below, you can unsubscribe at any time.

Subscribe to my newsletters...
Email:

On With The Show

Here is a list of the SNAPPS templates for Lotus Quickr and other free resources on QuickrTemplates.com:
Templates:
QContacts
QIdeas
QIssues
QMeeting
QPhotos
QPresent
QProject
QSite
QSurvey

Utilities:
AnyPlace SiteMap
AnyPlace ServerMap
AnyPlace Designer for Dreamweaver

Apps:
PandaBear: Cross-Platform File Management
Flippr: Lightweight Quickr Admin Client
SnappFiles: iPhone Client for Quickr, Filenet, ICM...

Downloads: 118,490
Countries: 162
Read about the templates in Intranet Journal
NEW: Some of the templates are now bona-fide products for Quickr 8.5.1! Check out my Sep 23 2011 entry for more!

Search

Googleage

  • No Search Referers