Perfect - unbreakable Ajax Function

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Jezternz
    New Member
    • Jan 2008
    • 145

    Perfect - unbreakable Ajax Function

    Ok basicly I want a function where I can enter several parameters, and be able to use this function multiple times. This is an example of what I want, first commented.
    Also note i am aiming for high efficiency.
    Code:
    function QueryUrl(type, url, returnFunction){
    // where type is a choice between post and get.
    // url is obviously the url you want to retrieve information from
    // returnFunction is a function that will be run, and passed across the returned data as a parameter (when it has retrieved the data) 
    }
    It is really the third parameter that is the part I need the most help with.
    An example of use is:
    Code:
    QueryUrl('POST', 'tryregister.php', updateNow);
    function updateNow(returnedData){
     document.getElementById('main_content').innerHTML = returnedData;
    }
    So you get the idea, of how I want to be able to use it. The third parameter is a reference to which function to call on retrieval of the data.
    Now using bits and pieces of the net. I have an attempt at queryurl.js (this is the part i need help on / my question is on) - this is incomplete and could possibly be more efficient:
    Code:
    function QueryUrl(type, url, returnFunction){
     var xmlHttp=GetXmlHttpObject();
    	if (xmlHttp==null){
    		alert ("Browser does not support HTTP Request");
    		  return;
    	}
    	xmlHttp.onreadystatechange=stateChanged;
    	xmlHttp.open(type,url,true);
    	xmlHttp.send(null);
    
     function stateChanged(){ 
    	if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete"){ 
    		returnFunction(xmlHttp.responseText);
    	} 
     }
    
     function GetXmlHttpObject(){
    	var xmlHttp=null;
    	try{
    		xmlHttp=new XMLHttpRequest();
    	}catch (e){
    		try{
    			xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
    		}catch (e){
    			xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
    		}
    	}
    	return xmlHttp;
     }
    
    }
    I get the feeling the post method wont work, offcourse im rather unsure about most of this.

    Thanks in advance, Josh
  • Jezternz
    New Member
    • Jan 2008
    • 145

    #2
    After a fair bit of messing around, and alot of guessing I think I got something that works, for anyone that wants to test it, or suggest improvements or use it themselves in the future go ahead :).

    Code:
    function AjaxQuery(type, url, parameters, qfunction){
    	if(url == "")return;
    	if(parameters == undefined)parameters = "";
    	
    	var xmlHttp=GetXmlHttpObject();	
        if (xmlHttp==null){alert ("Browser does not support HTTP Request");return;}
        
        xmlHttp.onreadystatechange=function(){
    		if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete"){
    			if(qfunction != undefined)qfunction(xmlHttp.responseText);
    		}			
    	}  
        if(type=="GET"){
      		xmlHttp.open("GET", url+"?"+parameters, true);
    	    xmlHttp.send(null);
    	} else {
        	xmlHttp.open("POST", url, true);
        	xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    		xmlHttp.setRequestHeader("Content-length", parameters.length);
    		xmlHttp.setRequestHeader("Connection", "close");
    		xmlHttp.send(parameters);
    	}
    }
    function GetXmlHttpObject(){
    	var xmlHttp=null;
    	try{
    		xmlHttp=new XMLHttpRequest();
    	}catch (e){
    		try{
    			xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
    		}catch (e){
    			xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
    		}
    	}
    	return xmlHttp;
    }
    Thanks Josh

    Comment

    • rnd me
      Recognized Expert Contributor
      • Jun 2007
      • 427

      #3
      Code:
      
      function AjaxQuery(url, qfunction, parameters, post ){
          if(!url){return;}
      	 parameters = parameters || "";
      
          var xmlHttp= !window.XMLHttpRequest ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
      
          if (!xmlHttp){alert ("Browser does not support HTTP Request");return;}
       
          xmlHttp.onreadystatechange=function(){
              if (xmlHttp.readyState==4 || xmlHttp.responseText){
                  if(qfunction){ qfunction.apply( xmlHttp, [xmlHttp.responseText, xmlHttp.status]);}
              }            
          }  
      
          if(!post){
                xmlHttp.open("GET", url +"?"+parameters, !!qfunction);
              xmlHttp.send(null);
          } else {
              xmlHttp.open("POST", url, !!qfunction);
              xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
              xmlHttp.setRequestHeader("Content-length", parameters.length);
              xmlHttp.setRequestHeader("Connection", "close");
              xmlHttp.send(parameters);
          }
      }
      CHANGES:

      -turned it into one function.
      -killed the global.
      -reduced code size by restructuring
      -removed the error-hiding try/catch: makes debugging easier.
      -defaults to sync, switches to async if callback is used
      -added the status as second argument to callback
      -"this" in callback refers to xmlhttp object itself
      -made type and parameters optional > defaults to "GET"
      -re-ordered arguments for most common usage.



      it can handle simple or complex usage as needed:
      Code:
      // ARGS:  (url, [qfunction], [parameters], [type])
      	alert(AjaxQuery("test.php")); //sync: AjaxQuery function returns text (GET)
      	AjaxQuery("test.php", function(a){ alert(a);}); //asynch GET  w/callback
      	AjaxQuery("test.php", function(a){ alert(a);}, "name=fred&age=21"); //asynch w/callback w/params (GET)
      	AjaxQuery("test.php", function(a){ alert(a);}, "name=fred&age=21", true ); //asynch w/callback w/params (POST)
      	AjaxQuery("test.php", function(a){ alert(a);}, "name=fred&age=21", "POST"); //asynch w/callback w/params (POST)
      	AjaxQuery("test.php", function(a){ alert(a);}, "name=fred&age=21", 1); //asynch w/callback w/params (POST)
      	alert(AjaxQuery("test.php"),"","", true); //sync: AjaxQuery function returns text (POST)

      Comment

      • Jezternz
        New Member
        • Jan 2008
        • 145

        #4
        wow thats awesome, thanks heaps man, looks very efficient.

        3 questions:

        First, do we need to add a random number parameter to the get statement so that the page is refreshed whenever its called, not just retrieval of a cached page? ie, within the if(!post) statement change it to:
        xmlHttp.open("G ET", url +"?" + parameters +"&random =" + Math.floor(Math .random() * 9999999), !!qfunction);
        I'm not sure about this? maybe you allowed for this?

        Second, so can I pass a function as a reference
        like this:
        AjaxQuery("test .php", myfunction);
        instead of this:
        AjaxQuery("test .php", function(a){ alert(a);});
        because sometimes I expect to have a large function and it seems a bit messy to put it as a parameter.

        Third, I don't understand what the !! means in this code, because I thought that just meant not, and two would mean they just cancel each other? and also why pass the function as a parameter to the xmlhttp.open, what is the third parameter for exactly?
        xmlHttp.open("P OST", url, !!qfunction);

        Anyways, thanks heaps, I can tell you know what your doing.
        Cheers, Josh

        Comment

        • rnd me
          Recognized Expert Contributor
          • Jun 2007
          • 427

          #5
          3 questions:

          First, do we need to add a random number parameter to the get statement so that the page is refreshed whenever its called, not just retrieval of a cached page? ie, within the if(!post) statement change it to:
          xmlHttp.open("G ET", url +"?" + parameters +"&random =" + Math.floor(Math .random() * 9999999), !!qfunction);
          I'm not sure about this? maybe you allowed for this?

          that's not a terrible idea. i like using this between open and send to do the same thing
          :
          Code:
          xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
          Second, so can I pass a function as a reference
          like this:
          AjaxQuery("test .php", myfunction);
          instead of this:
          AjaxQuery("test .php", function(a){ alert(a);});
          because sometimes I expect to have a large function and it seems a bit messy to put it as a parameter.
          yes, functions are functions and names point to functions, so that all works.


          Code:
          Third, I don't understand what the !! means in this code, because I thought that just meant not, and two would mean they just cancel each other? and also why pass the function as a parameter to the xmlhttp.open, what is the third parameter for exactly?
          xmlHttp.open("POST", url, !!qfunction);

          in javascript, certain variable value are considered to be "thruthy" and "falsey".
          true includes: " ",1,true,!0 ,[1,2,3],{},/./, and function a(){}.
          false includes "",0,false,null , and undefined.

          basically non blanks, non-null, non-zero, or object values are all "truthy"

          the "!" operator converts a value into its Boolean equivalent.

          eg: !5 === false.

          not not means convert to Boolean opposite, then the opposite of that.

          in the open method, the presence of a call back triggers a true to be passed to the ajax third parameter: forcing it into async mode.

          when you omit the callback function, it goes into sync mode, and the AjaxQuery function itself returns the string of the URL. this simplifies coding, but also freezes the browser interface (and script execution) while the file downloads.

          Comment

          • Jezternz
            New Member
            • Jan 2008
            • 145

            #6
            thanks again rnd-me, I am sure I will be using this function alot in the future.

            Just to clarify the final product is:
            Code:
            function AjaxQuery(url, qfunction, parameters, post ){
            	if(!url){return;}
            	parameters = parameters || "";
            
            	var xmlHttp= !window.XMLHttpRequest ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
            
            	if (!xmlHttp){alert ("Browser does not support HTTP Request");return;}
            
            	xmlHttp.onreadystatechange=function(){
            		if (xmlHttp.readyState==4 || xmlHttp.responseText){
            			if(qfunction){ qfunction.apply( xmlHttp, [xmlHttp.responseText, xmlHttp.status]);}
            		}            
            	}  
            
            	if(!post){
            		xmlHttp.open("GET", url +"?"+parameters, !!qfunction);
            		xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
            		xmlHttp.send(null);
            	} else {
            		xmlHttp.open("POST", url, !!qfunction);
            		xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            		xmlHttp.setRequestHeader("Content-length", parameters.length);
            		xmlHttp.setRequestHeader("Connection", "close");
            		xmlHttp.send(parameters);
            	}
            }
            -This is your previous code with the "xmlHttp.setReq uestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");" added into the GET part (the POST part doesnt need it im guessing??)

            Comment

            • rnd me
              Recognized Expert Contributor
              • Jun 2007
              • 427

              #7
              looks good to me.

              i may have to "borrow" this sometime.

              cheers!

              Comment

              • acoder
                Recognized Expert MVP
                • Nov 2006
                • 16032

                #8
                Just a note: you may want to encode parameters in case there are any special characters, e.g. & % =

                Re. cache busting. A header's good, but if you were using Math.random, I'd have suggested Date.getTime.

                Comment

                • Jezternz
                  New Member
                  • Jan 2008
                  • 145

                  #9
                  Thanks for the heads up acoder, i never thought of that.
                  I will look into encoding % = later in the week, however we cant really do it with & (as i understand it), as it is unknown which parts of the parameter are legit ampersands (to separate parameters) as opposed to which ones are entries (though i am sure you both already know this). Maybe write a function for use when joining the parameters when AjaxQuery is used, maybe VerifyParameter which would return the new formatted string.

                  Aside from that, half the reason I made this thread was so that, others could come and find it and use it, and not have to make such an important ajax function themselves. Thanks heaps rnd me, you more then anyone should be able to use it.

                  Cheers, Josh

                  Comment

                  • acoder
                    Recognized Expert MVP
                    • Nov 2006
                    • 16032

                    #10
                    Yes, I meant ampersands within the parameter name or value. You can use an object of name/value pairs, e.g. { name: 'fred', age: '21', interests: 'javascript & ajax' } and loop over them to encode them.

                    Comment

                    • Jezternz
                      New Member
                      • Jan 2008
                      • 145

                      #11
                      yeh I understand what you mean, but as I understand it the parameters are currently all stored in a single string like so:
                      "name=fred&age= 21&interests=ja vascript & ajax" which as you can see, there is no logical way for the script to tell the difference from
                      a new parameter eg &interests
                      and a parameter with a ampersand in it eg &interests=java script & ajax

                      So another outside function may be required?

                      cheers, Josh

                      Comment

                      • acoder
                        Recognized Expert MVP
                        • Nov 2006
                        • 16032

                        #12
                        Not necessarily. If instead of a string, you passed an object, you could deal with it quite easily within the function. Alternatively, you could just leave it to the user to ensure that they encode strings with special characters before passing in the parameters as strings.

                        Comment

                        Working...