JavaScript

Debugging Your JavaScript Code the Easy Way

Tagged:  

When developing Ajax applications finding a good JavaScript debugger is very important. If you have ever tried to debug JavaScript in Internet Explorer you know how bad the error messages can be. This has been the reason that many developers have thought of JavaScript as only good for a couple of effects (such as rollovers). The error console in Firefox does a much better job of actually pointing you in the right direction, but this can be better. Below is a list of good tools that will help ease the pain of JavaScript debugging.

The first good tool for debugging JavaScript is JSLint. JSLint is a free web application where you copy and paste your code into the site and it will check the code for you line by line. It does a good job of catching quite a few errors and will recommend some good coding practices. Unfortunately, the site will just list your errors and you have no options to step through your code.

jslint.jpg

The next tool is the Venkman debugger in Firefox. Venkman does a good job of finding errors and is closer to a traditional debugger. Venkman is a free plug in for Firefox that comes packaged with the browser, but when you install it you have to select the correct options to install it. The plug in can also be downloaded from Mozilla's site. The debugger allows for you to step through your code and gives a good overview of what is being called in the code. Venkman is a very good tool when you are chasing down a pesky bug in your code.

walkthrough-overview-large.gif

The third debugger is Firebug. While on the surface Firebug is very similar to Venkman (they are both browser plug ins for Firefox and both offer good step through functionality) where Firebug really differentiates itself is that it can find some obscure problems in your code that most debuggers would not catch. Firebug also has some great functionality where you can set break points only when a certain condition is met.

firebug.jpg

The last debugger is for the MyEclipse Pro IDE and is called the Eclipse JavaScript Debugger. The JavaScript debugger is pretty good and it gives you more of an IDE feel when your are doing your debugging. The debugger is part of the Ajax Workbench which gives you some great tools to debug your Ajax applications. The biggest downside to this toolkit is that it is not free for the debugger nor the IDE (since it requires the MyEclipse Pro IDE). This debugger is mainly useful for large enterprises as they will be more likely to pay for this type of tool.

This is just a quick roundup of what I think are some of the best JavaScript debuggers. While there are more debuggers available (such as included in Tibco's General Interface) these are some very good debuggers that are useful to most developers. If you use a debugger that is not mentioned here I would love to hear about it, so leave it in the comments.

Dynamic Loading of JavaScript without using Eval

In trying to create faster loading Ajax applications it is important to reduce the amount of code that is downloaded. One of the best ways to accomplish this is to dynamically load JavaScript as you need it. This will allow that the initial load time is very short.

There are a few ways to accomplish this. One is to have multiple JavaScript files that are loaded using either eval or DOM manipulation (since I am of the school of eval is evil I will use DOM manipulation). The other is to have a server side script (such as a php or ruby script) dynamically create the needed JavaScript based on parameters that are passed through the URL and once again it would be loaded using either eval or DOM manipulation.

No matter which method you choose to use the below code will work to dynamically load the JavaScript. For those of you who have read my post on the JSON Load Object without using Eval (Click here to read the article) the following code will look very familiar as the methods are very similar.

//Dynamic JavaScript Creation
var javascriptload=new Object();
javascriptload.CreateObject=function(codeholderid, url){
	this.codeholderid=codeholderid; //This is the id of the element to hold the script code
	this.url = url;
	this.loadjavascript(codeholderid, url);
};
javascriptload.CreateObject.prototype={
	loadjavascript:function(codeholderid, url){
		var JavaScriptCode=document.createElement("script");
		JavaScriptCode.setAttribute('type', 'text/javascript');
	        JavaScriptCode.setAttribute("src", url);
		document.getElementById(codeholderid).appendChild(JavaScriptCode);
	}
};

In the above code you would pass in the id of the element to hold the JavaScript (this can be a div, body tag or any other tag that can hold a script tag) and you would pass in the URL to the JavaScript (either the separate JavaScript files or the dynamically created JavaScript).

Now that you have the object to dynamically load JavaScript go through your applications and reduce the initial load time in your Ajax applications. You might be surprised just how much faster you can get your applications to load.

Google Ajax Feed API + Flickr Photo Feed + Mootools Image Reflection

Introduction
So this all started because I decided to play around with the Google Ajax Feed API, integrate it with the Flickr public photo feed, and add a Mootools Image Reflection script in to the mix to spice things up a bit.

Let's start with the Google Ajax Feed API and what it offers. With the AJAX Feed API, you can download any public Atom or RSS feed using only JavaScript, so you can easily mash up feeds with your content and other APIs like the Google Maps API. If you haven't had a chance to dig into it, you should. It's relatively simple and straightforward, is very quick to set up, and runs like a champ. First, you'll need to sign your site up for a API Key here.

Now let's take a look at the Flickr Photo Feed. Flickr is one of the biggest online photo management and sharing application in the world. They offer a free full blown API, but for this project I only used their public photo feed.

Finally, the third ingredient in this melting pot is an image reflection script based on the Mootools framework. Image reflection has become much more common in the Web 2.0 design style. This script provides a code based solution to creating reflections as opposed to hand creating them in an image editor like Adobe Photoshop. If you're not sure what I mean by image reflections, stay tuned for a quick and dirty demo.

Google Ajax Feed API
To begin using the Ajax API in a page, you first need to include the javascript code from google's server in your header, passing it your API key:

<script type=\"text/javascript\" src=\"http://www.google.com/jsapi?key=[your api key here]\"></script>

Next, initialize the API by calling

google.load("feeds", "1");

Specify your callback function by calling google.setOnLoadCallback(initialize); where initialize is the name of our callback function.


Finally, let's build the initialize function, to process the Flickr public feed after the API is ready.

function initialize() {      
	// this random number is used to guarantee we aren't getting a cached copy of the feed, which by default is in JSON format
	var randomnumber=Math.floor(Math.random()*1000000);
	
	// the flickr feed url is used to instantiate a new google feed object
	var feed = new google.feeds.Feed("http://api.flickr.com/services/feeds/photos_public.gne?rand="+randomnumber);

	// The container is a DIV that contains all the photos retrieved from Flickr
	// Each time this method is called, we need to erase the previous photos
	// with a little DOM manipulation
	var container = document.getElementById("feed");
	if(container != null){
		container.parentNode.removeChild(container);				
	}
	container = document.createElement("DIV");
	container.id = "feed";
	container.innerHTML = "<p class=\'loading\'>Loading...</p>";
	document.body.appendChild(container);

	// setNumEntries allows us to specify the number of elements Google will return
	// in the feed, the default is 4
	feed.setNumEntries(20);

	// we execute the load method to tell the api to fetch our feed
	// and we pass it our callback function
	feed.load(function(result) {
            if (!result.error) {               
	  // this removes our loading message
	  container.innerHTML = "";

	  // we loop through our result set (a JSON object)
              for (var i = 0; i < result.feed.entries.length; i++) {
	       // for each entry, we create a div, assign it a css class name,
	       // create a hyperlink back to the Flickr page contain the fullsize picture
	       // and create an image node for our thumnail
                   var entry = result.feed.entries[i];			
                   var div = document.createElement("div");
                   div.className = "imageDIV";			
                   var linkNode = document.createElement("a");
                   linkNode.href = entry.link;
                   linkNode.target = "_blank";				
                   var imageNode = document.createElement("img");
                   imageNode.id = "image"+i;
	       // parseImgURL is a method I wrote to parse out the thumbnail url from a node in
	       // in the JSON object since that contained other content
                   imageNode.src = parseImgURL(entry.content);
                   imageNode.border = 0;

	       // add the hyperlink to the image	, assign it to the div, and put it on the page
                   linkNode.appendChild(imageNode);		
                   div.appendChild(linkNode);
                   container.appendChild(div);

	       // finally, this one-liner is all we need to activate the reflection
	       // feature on the image we just added to the page. The first parameter
	       // in the add method is the image id, the second parameter is used for options
	       // like the height and opacity of the reflection. 
	       // .8 results in a reflection that is 80% of the height of the original image
                   Reflection.add('image'+i, {height:.8});
              }


            }
          });
}

Flickr Photo Feed
More information on the Flickr API can be found on their website.
For this project, I chose to only use their public feed (which doesn't require an API key).

Mootools Image Reflection
This script works in all browsers supporting the canvas tag: Firefox since version 1.5, Camino, Opera since version 9 and Safari since version 1.3. It also works in Internet Explorer 5.5 and more recent by using an alternative drawing technique.

Take a look at the Demo

Sources
Google Ajax Feed API: http://code.google.com/apis/ajaxfeeds/
Flickr Photo Feed: http://www.flickr.com/services/feeds/docs/photos_public/
Mootools Image Reflection Script: http://www.digitalia.be/software/reflectionjs-for-mootools

A Better Ajax Back Button Solution

If you've spent any time coding an Ajax application you know that the one of the problems with Ajax is that it breaks the back button. You have probably seen solutions that use an iframe and a hash (#) in the url to fix this issue. While this works there is a much simpler way that I've been using in my applications for the last year or so.

The key is the A tag (also known as the anchor tag) and the name parameter with a hash in the url. The trick is to either dynamically create the element or to just change the value of the name parameter to the matching value of the hash.

Below is an example of changing the name of the anchor tag.

//Anchor Rename Object this could also be a simple function if preferred.
var AnchorRename=new Object();
AnchorRename.CreateObject=function(anchorname, anchorid){
	this.anchorid=anchorid; //This is the id of the anchor element
	this.anchorname=anchorname;
	this.RenameAnchor(anchorname, anchorholerid);
};
AnchorRename.CreateObject.prototype={
	RenameAnchor:function(anchorname, anchorid){
		document.getElementById(anchorid).name = anchorname;
	}
};

In this example you would pass in the new value of the name (which must be the same value as after the hash in the url) and the id of the anchor element.

Below is an example of dynamically creating the tag and name values.

//Anchor Rename Object
var AnchorRename=new Object();
AnchorRename.CreateObject=function(anchorname, anchorholderid){
	this.anchorholerid=anchorholderid; //This is the id of the element to hold the new anchor
	this.anchorname=anchorname;
	this.RenameAnchor(anchorname, anchorholderid);
};
AnchorRename.CreateObject.prototype={
	RenameAnchor:function(anchorname, anchorholderid){
		var AnchorCode=document.createElement("a");
	        AnchorCode.setAttribute("name", anchorname);
		document.getElementById(anchorholderid).appendChild(AnchorCode);	       
	}
};

In this example you would pass in the new value of the name (which again must be the same value as after the hash in the url) and the id of the anchor element.

Now the question that you may be asking is how does creating or renaming the anchor element help with fixing the back button. That is where when you call the object comes into play. You need to create or rename the object before a link is clicked. So, I would recommend using an onmouseover and an onfocus event to call the create or rename of the element so that before a link is clicked the required anchor element will be created.

I hope that this post has shown an easier solution to fix the back button problem that occurs when we create Ajax applications. Now go out there and try using it on your applications!

Update: I have posted a working example of this solution and it can be read here.

A JSON Load Object without using Eval

Tagged:  

After writing my article on using JSON in Ajax without using Eval (click here to read the original article) I thought that it would be easier to have an object that could create the JSON with DOM manipulation. So below is the code for the object.

//JSON Dom Code
var jsonload=new Object();
jsonload.CreateObject=function(codeholderid, jsoncode){
	this.codeholderid=codeholderid; //This is the id (as a string) of the element to hold the script code
	this.jsoncode=jsoncode;
	this.loadJSON(codeholderid, jsoncode);
};
jsonload.CreateObject.prototype={
	loadJSON:function(codeholderid, jsoncode){
		var JSONCode=document.createElement("script");
		JSONCode.setAttribute('type', 'text/javascript');
		JSONCode.text = jsoncode;
		document.getElementById(codeholderid).appendChild(JSONCode);	       
	}
};

This code works by passing in the id of the element that should hold the script and the text of the code that should be run (this could also be used to dynamically load code). This code is great if you are going to use an Ajax call that calls content from the same domain (or if you use a server side proxy that tricks it into working). However, if you want to get your JSON from a cross domain you could use the below code.

//JSON Dom Code
var jsonload=new Object();
jsonload.CreateObject=function(codeholderid, jsoncode, url){
	this.codeholderid=codeholderid; //This is the id of the element to hold the script code
	this.jsoncode=jsoncode;
	this.url = url;
	this.loadJSON(codeholderid, jsoncode, url);
};
jsonload.CreateObject.prototype={
	loadJSON:function(codeholderid, jsoncode, url){
		var JSONCode=document.createElement("script");
		JSONCode.setAttribute('type', 'text/javascript');
	        JSONCode.setAttribute("src", url);
		document.getElementById(codeholderid).appendChild(JSONCode);	       
	}
};

In this code you would pass in the same arguments as the first example plus the additional url argument. The url can be to server side code that would create the JSON that could be based on parameters that are passed in through the url.

Below is an example that shows how the first example code would work with an Ajax call.

//Ajax Object Code
var net=new Object();
net.READY_STATE_UNINITIALIZED=0;
net.READY_STATE_LOADING=1;
net.READY_STATE_LOADED=2;
net.READY_STATE_INTERACTIVE=3;
net.READY_STATE_COMPLETE=4;
net.ContentLoader=function(url, onload, onerror, callingobject){
	this.url=url;
	this.req=null;
	this.callingobject=callingobject;
	this.onload=onload;
	this.onerror=(onerror) ? onerror : this.defaultError;
	this.loadXMLDoc(url);
};
net.ContentLoader.prototype={
	loadXMLDoc:function(url){
	        if(window.XMLHttpRequest){
	                this.req=new XMLHttpRequest();
	                if (this.req.overrideMimeType) {
          			 this.req.overrideMimeType('text/xml');
		        }
	        } else if (window.ActiveXObject){
	                try {
           			this.req=new ActiveXObject("Msxml2.XMLHTTP");
			} catch (err) {
				try {
					this.req=new ActiveXObject("Microsoft.XMLHTTP");
			} catch (err) {}
			}
	        }
	        if(this.req){
	                try{
				var loader=this;
	                        this.req.onreadystatechange=function(){
	                                loader.onReadyState.call(loader);
	                        };
	                        var TimeStamp = new Date().getTime();//This fixes a cache problem
	                        if(url.indexOf("?")<0){
		                        this.req.open('GET', url+"?timestamp="+TimeStamp, true);
	                        }else{
	                                this.req.open('GET', url+"×tamp="+TimeStamp, true);
	                        }
	                        this.req.send(null);
	                } catch (err){
	                        this.onerror.call(this);
	                }
	        }
	},
	onReadyState:function(){
	        var req=this.req;
	        var ready=req.readyState;
	        if(ready==net.READY_STATE_COMPLETE){
	                var httpStatus=req.status;
	                if(httpStatus==200||httpStatus===0){
	                        this.onload.call(this);
	                } else {
	                        this.onerror.call(this);
	                }
	        }
	},
	defaultError:function(){
	        alert("error fetching data!" + "\n\nreadyState: "+this.req.readyState + "\nstatus: "+this.req.status+"\nheaders: "+this.req.getAllResponseHeaders());
	}
};

//JSON Dom Code
var jsonload=new Object();
jsonload.CreateObject=function(codeholderid, jsoncode){
	this.codeholderid=codeholderid; //This is the id of the element to hold the script code
	this.jsoncode=jsoncode;
	this.loadJSON(codeholderid, jsoncode);
};
jsonload.CreateObject.prototype={
	loadJSON:function(codeholderid, jsoncode){
		var JSONCode=document.createElement("script");
		JSONCode.setAttribute('type', 'text/javascript');
		JSONCode.text = jsoncode;
		document.getElementById(codeholderid).appendChild(JSONCode);	       
	}
};

function StartJSONLoad(url, callingobject){
	//url is the url of the server side script to get the JSON
	//callingobject is the id of the element that is making the ajax call
	var AJAXConnection = new net.ContentLoader(url, FinishJSONLoad, JSONError, callingobject);
}
function FinishJSONLoad(){
	var codeholderid="DivHolder"; //Where DivHolder is the id of the element where the script should be created.
	var JSONObject = new jsonload.CreateObject(codeholderid, this.req.responseText);
}
function JSONError(){
        alert("There was an issue getting the data.");
}

To use this code you simply have to call the StartJSONLoad function and pass in the URL for the Ajax call (this would go to some server side code that would return the JSON) and the element that is calling the code [you have to use the document.getElementById('idofelement')] which could be the element that will hold the script. In the FinishJSONLoad function you will need to change the DivHolder string to the id of the element that you would like to hold the JSON code.

I hope this code makes it easy to start using JSON in your web applications without using the "evil" eval!

For more information on JSON visit json.org.

Syndicate content