jx Library Explained

jx is a small toolkit for providing AJAX support in JavaScript. It supports GET and POST method. The supported return types are plain text and JSON. It does NOT support XML return. This page attempts to explain the inner working of this script - line by line.

This 'library' is created using Object Notation - so the variables used in the library will not step on the toes of the other variables in the global scope of your script. For example, if you are using a variable called 'http' in the global scope, you need not worry about how it will affect the variable used in the library - it won't. That is because the http variable of JX exists in an object called jx and can only be accessed by jx.http.

Now lets move on to the code. Please note that this library is in constant development and will be updated in the future. The version we are using is V 3.00.A. Future versions will have more features.

var jx = {

First we create the jx object - this will hold all the functions and variables for this library. All the member functions can be accessed only through this object(eg 'jx.init();').


	http : false,// We create the HTTP Object
	format : 'text',
	callback : function(data){},
	error:false,

Next, we declare some variables that will be used through out the object - here there are only two of them - the http variable and the format variable. There is also the callback and error function. The use of these variables will be clear as we continue down.


	//Create a xmlHttpRequest object - this is the constructor. 
	getHTTPObject : function() {

We create a function called getHTTPObject() - this function will return a XMLHttpRequest object based on browser.


		var http = false;

The http variable holds the XMLHTTPRequest object. Its initial value is false - if its value is false at the end of the function, that means that the browser used by the vistor don't support advanced javascript that is necessary for AJAX apps.


		//Use IE's ActiveX items to load the file.
		if(typeof ActiveXObject != 'undefined') {
			try {http = new ActiveXObject("Msxml2.XMLHTTP");}
			catch (e) {
				try {http = new ActiveXObject("Microsoft.XMLHTTP");}
				catch (E) {http = false;}
			}

Then the script tries to see if ActiveXObject is available on the users browser. We need ActiveX support to run AJAX scripts in Microsoft Internet Explorer. Here, two different versions of MSXML are supported - if either is present, we will have AJAX support.


		} else if (XMLHttpRequest) {
			try {http = new XMLHttpRequest();}
			catch (e) {http = false;}
		}

If MSXML is not present, the script will look for the XMLHTTPRequest support - this is supported by the other browsers - Firefox, Mozilla, Opera, Safari etc. If present, the script will use this feature for AJAX.


		return http;
	},

Here, the function returns the XMLHTTPRequest object if this feature is supported. If it is not support, false will be returned.


	load : (url,callback,format) {

Our next function is the load function. This function should be called when an Server Side script is to be executed. This function was called in our example like this...


		//Sample of how the jx library is used
		jx.load("save_data.php?comment=" + $("comment").value + "&email=" + $("email").value,function(){});//We have saved the data.

As you see, we have four arguments for this function -

url
The URL of the server side script and the data that must be posted to that page using the GET method.
callback
The function that must be called when the given URL is loaded. This function will be called with an argument - the data in plain text format if the given return type is 'text' or as an object if the return type is 'json'.
format
The return type for the Server side script. If it is JSON, the library will eval the returned text before passing it to the callback function.

		this.init(); //The XMLHttpRequest object is recreated at every call - to defeat Cache problem in IE
		if(!this.http||!url) return;

This code will initialization the jx engine. We have to do this every time the load function is called because IE have a problem with its cache - the same results will be given as the responseText even if there is changes in the text.. If AJAX is not supported in this browser, the function will not continue.


		this.callback=callback;

Store the callback function as a function of the jx object. This is necessary as we will have to call it from the handler function.

		
		if(!format) var format = "text";//Default return type is 'text'
		this.format = format.toLowerCase();

Set the defaults for format and method if none are provided. If a format or method is specified by the user, use that. Sets the default return type as 'text'. This will return the output of the server side script just as it is into the function specified as the callback function.


		var ths = this;//Closure

This is a tricky concept to grasp if you don't know what a closure is. If you wish to understand what a closure is, I will recommand the 'JavaScript Closures for Dummies' article. Basically, any variable created in this function will be available in all functions created inside this function. A few lines down we will create a function to handle the state change for the XMLHttpRequest - the 'ths' variable will be available inside that function - without making it a global variable. Here we give the current instance of the 'jx' object(this) to the variable 'ths'. This is done so that we can access the current instance from within the state change handler. The 'this' variable will to be available inside that function as it will be overwritten. I know that this paragraph was a little hard to understand - I can't do anything about it. You have to know 'closures' before you can make head or tail of the above description.


		//Kill the Cache problem in IE.
		var now = "uid=" + new Date().getTime();
		url += (url.indexOf("?")+1) ? "&" : "?";
		url += now;

Ensuring that IE will not make any cache problems - by giving a unique URL for every request. A unique id is made from the current time(with seconds) and appended to the URL. As it is always changing, the URL will not be repeated.


		this.http.open("GET", url, true);

Here, we open the given url using the XMLHTTPRequest object. The three arguments for this function are...

Method
GET, POST or HEAD. This argument specify which method must be used in transporting the given data to the new file. Using the GET method, we will be able to pass the data to the server side script in the url itself - like this url.php?data=value. The POST method will send the data after the connection is opened. The HEAD method can be used to get the headers of the url without having to download the entire page. The default method used in jx is 'GET'.
URL
The URL of the file that must be opened - the location of the server side script. This can be a absolute URL like(http://www.openjs.com/feedback.php) or a relative one(../../feedback.php). A note of caution - this URL should be in the same domain as the script is. You cannot call a script in google.com from a script that is running in yahoo.com. This is a security measure implemented in most browsers to prevent XSS.
Asynchronous/Synchronous
This argument will be true if the request is asynchronous and false if it is synchronous. If it is Synchronous, the browser will suspend all activity till the response is received. This causes firefox to freeze up. Asynchronous requests don't have this problem - they will download the new page in the background - allowing the user to do other things.

		this.http.onreadystatechange = function() {//Call a function when the state changes.

The XMLHTTPRequest object has a property called the ready state. It can have 5 values...

jx.http.readyState == 0
The request is not initialized (This is the state it has before you've called the open() function).
1
The request is ready, but not sent - when you have called open() but before you've called send()(We will call this function later).
2
The request was sent at this point - the headers of the response are usually available now.
3
The browser is downloading the requested data - headers and the some partial data may be available, but the server isn't finished with its response.
4
The download is complete - now you can receive and use the response.

			if(!ths) return;
			var http = ths.http;

If the closure variable 'ths' is not available, exit the function. Also create a variable 'http' to act as a shortcut while accessing ths.http.


			if (http.readyState == 4) {//Ready State will be 4 when the document is loaded.

We check wether the readyState is 4 - continue only if the ready state is 4.


				if (http.status == 200) {

Check the response status - this will be 200 for all proper responses. If we get a file not found error, we will get 404 as the status. See the HTTP specification to find about other status codes.


					var result = "";
					if(http.responseText) result = http.responseText;

Get the response into a variable called result as a string. This is the contents printed by the server side script.


					//If the return is in JSON format, eval the result before returning it.
					if(jx.format.charAt(0) == "j") {
						result = result.replace(/[\n\r]/g,"");//\n's in the text to be evaluated will create problems in IE
						result = eval('('+result+')'); 
					}

If the return type is JSON, eval the returned text before returning it. This will execute the given string and store the result in a variable called, um, result. I have also removed all the new line chars in the given JSON code as it sometimes causes errors in IE when this code is evaluated.


					//Give the data to the callback function.
					if(jx.callback) jx.callback(result);

If the given callback function exists, this line will call the function with the returned result as the argument. We can define the callback function - so we can do custom operations on the returned data. The function don't have to be named callback() - as a matter of fact, it don't have to be named anything - it can be an anonymous function. Remember the code
load : function(url,callback,format) {'
See the second argument - callback - that argument is actually a function. Yes, a function can be a given as an argument for another function - ain't JavaScript cool?


				} else { //An error occured
					if(ths.error) ths.error(status)
				}

If the status for the connection is not '200', then there is a problem. The ths.error() function to be called if there is an error. The 'error' function is empty by default - the user can specify the funciton.


			}
		}

Close all the open blocks - the if conditions for http.readyState and the state change handler function.


		this.http.send(null);
	},

This will send the request. The url is loaded only after this line is called. As we are using the GET method the parameter will be a null value.


	init:function(){this.http=this.getHTTPObject();}
}

Get the XMLHTTPRequest object and stores it in the http variable. This function is called from the load function.

blog comments powered by Disqus