Debugging jQuery Code

I use jQuery quite a lot now and have found that it helps enormously to know how to properly debug it without resorting to javascript alert boxes. Firefox is my weapon of choice and still seems to be way easier to control than IE developer tools or even Chrome (yet!).

jQuery – Unobtrusive Code

A major benefit of jQuery over standard inline javascript is that it keeps it out of the html markup.

Example:

 <script type="text/javascript">
$(function() {
    $('helloUnobtrusive').bind('click', function() {
       $(this).text('Hello Unobtrusive');
    });
 });
 </script>
<p id="helloObtrusive"
    onclick="$(this).text('Hello Obtrusive'); return false;">
    Hello Obtrusive JavaScript!
 </p>
 <p id="helloUnobtrusive">Hello Unobtrusive JavaScript!</p>

Makes much cleaner code and graceful degradation when javascript is turned off, but now it’s harder to debug.

Tools

Example HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<title>Sandbox</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { background-color: #000; font: 16px Helvetica, Arial; color: #fff; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
  <div>
     <a id="selectMe" href="http://johnayling.com">This is me...</a>
  </div>
  <pre><code>
   $('div a')
  </code></pre>
  <a href="http://johnayling.com" target="_blank">View, Run, & Edit Code</a>
</body>
</html>

Debugging Selectors

Starting point is getting the right selector.  From there you can attach events, and so on.

Using the Console tab on Firebug
$(‘div a’) returns jQuery(a#selectMe johnayling.com)
$(‘div a.incorrectClass’) returns jQuery( ) ie. nothing in the jQuery array as there is no match.

Using FireFinder
The goal is to find all the links referencing zip files with a title that starts with “John”

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example 2 - Selectors</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
  //Try to select all links referencing zip files w/ title's that begin w/ John (Note: This is wrong)
  $("div a[href$='.zip'][title*='John']").click(function() {
      console.log("I've been clicked!");
   });
</script>
</head>
<body>
   <div>
      <p><a href="http://johnayling.com/john1.gif">john1.gif w/ no title</a></p>
      <p><a href="http://johnayling.com/john2.zip">john2.zip w/ no title</a></p>
      <p><a href="http://johnayling.com/john3.zip" title="John, Pick Me! 1 of 3">john3.zip w/ prepended John title</a></p>
      <p><a href="http://johnayling.com/john4.zip" title="John, Pick Me! 2 of 3">john4.zip w/ prepended John title</a></p>
      <p><a href="http://johnayling.com/john5.zip" title="Pick Me John!">john5.zip w/ John in middle of title</a></p>
      <p><a href="http://johnayling.com/john6.zip" title="John, Pick Me! 3 of 3">john6.zip w/ prepended John title</a></p>
   </div>
   <pre><code>
   FireFinder: div a[href$='.zip'][title*='John']
   </code></pre>
</body>
</html>

div a[href$='.zip'][title*='John'] – wrong selector for finding ‘starts with’
div a[href$='.zip'][title^='John'] – right

Debugging Events

Another problem you might want to debug is where code has been attached to the wrong event or the event handler has been attached to the wrong element.

Using FireQuery
Example 3 – Firebug HTML tab

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example 3 - Events</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('#helloWorld').bind('click', function() {
      $(this).text('Hello John!');
   });
   $('#goodbyeWorld').live('click', function() {
      $(this).text('Goodbye John!');
   });
   $('#whoWroteThatSong').data('artist', 'THE BEATLES');
});
</script>
</head>
<body>
  <p id="helloWorld">Hello World!</p>
  <p id="goodbyeWorld">Goodbye World!</p>
  <p id="whoWroteThatSong">Hello Goodbye</p>
</body>
</html>

Hello world has click event attached to it.  Hover to see the function that will be executed on a click event.

Data key ‘artist’ is being used to store ‘THE BEATLES’ to the #whoWroteThatSong p element.

Debugging Using Breakpoints

Example 4

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example4 - Set Breakpoints</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('button').click(function() {
      var firstName = 'John';
      var lastName = 'Ayling';
      var fullName = firstName + ' ' + lastName;
      console.log("Your name is %s. I hope you have a great day!", fullName);
   });
});
</script>
</head>
<body>
   <p><button>Click Me</button></p>
</body>
</html>

Set breakpoint on line to see the code flow and variable values.
var firstName = ‘John’;
Can see control flow, stack traces and watch

Set to Automatically Break on Error

Set the Enable Break On All Errors feature in Firebug to start a debug session automatically when an error occurs.
You can turn on this feature by clicking the Pause button in the top menu on the Console tab.
You might have to select the ‘Script’ menu depending on which version of Firebug you are are using.
Example 5

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example 5 - Break on Error</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('button').click(function() {
      var firstName = 'John';
      var x = x.fakeFunctionCall();
      var lastName = 'Ayling';
      var fullName = firstName + ' ' + lastName;
      console.log("Your name is %s. I hope you have a great day!", fullName);
   });
});
</script>
</head>
<body>
   <p><button>Click Me</button></p>
</body>
</html>

How to Tell Which Element Has Triggered an Event

Look at watch window and as step into the function that has been triggered, look at the ‘this’ variable.
Example 6.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example 6 - Element Trigger</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial;}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('#helloWorld').bind('click', function() {
      $(this).text('Hello john!');
   });
   $('#goodbyeWorld').live('click', function() {
      $(this).text('Goodbye John!');
   });
});
</script>
</head>
<body>
  <p id="helloWorld">Hello World!</p>
  <p id="goodbyeWorld">Goodbye World!</p>
</body>
</html>

Set breakpoint on line $(this).text(‘Hello john!’);

How To Tell Where an Error Originates From When an Error is Coming From Helper Methods

Set a breakpoint and look at the Stack tab.
Example 7

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example 7 - Stack Trace</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('button').click(function() {
      console.log(fullName());
   });
});
function fullName() {
   return firstName() + ' ' + lastName();
}
function firstName() {
   return 'John';
}
function lastName() {
   return 'Ayling';
}
</script>
</head>
<body>
   <p><button>Click Me</button></p>
</body>
</html>

Put breakpoint on return ‘John’, view ‘Stack’ tab and follow path into the jQuery library code.

How To Determine Where A Bottleneck is Where Processing is Taking Too Long to Execute

This is a very handy thing to know and can very quickly help you hone into where your ‘client app’ is slowing down processing on the page. Ever got a browser warning box pop up that the script has gone on too long? – this is the first step in solving this.
Example 8

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example 8 - Profiler</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('button').click(function() {
      var randomNumberSum = 0;
      for (var i = 0; i < 100000; ++i) {
         randomNumberSum += getRandomNumber(10);
      }
      console.log('Random Number Sum: %d', randomNumberSum);
   });
   function getRandomNumber(maximumNumber) {
      return Math.floor(Math.random() * getNumberPlusOne(maximumNumber));
   }
   function getNumberPlusOne(number) {
      return number + 1;
   }
});
</script>
</head>
<body>
   <p><button>Click Me</button></p>
</body>
</html>

Click ‘Profile’ button, execute code, click ‘Profile’ button again to see performance statistics.

How to Inspect the Contents of An Ajax Call

Example – predictive search
http://www.infolink.com.au/
Look at GET request on ‘Console’ tab made when typing text into predictive search box

Using Conditional Breakpoints

Example 9

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Example 9 - Conditional Breakpoints</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { font: 16px Helvetica, Arial; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('button').click(function() {
      var randomNumberSum = 0;
      for (var i = 0; i < 100000; ++i) {
         randomNumberSum += getRandomNumber(10);
      }
      console.log('Random Number Sum: %d', randomNumberSum);
   });
   function getRandomNumber(maximumNumber) {
      return Math.floor(Math.random() * getNumberPlusOne(maximumNumber));
   }
   function getNumberPlusOne(number) {
      return number + 1;
   }
});
</script>
</head>
<body>
   <p><button>Click Me</button></p>
</body>
</html>

Set stop on randomNumberSum += getRandomNumber(10);
Right-click stop and enter expression 1 == 32

Leave a Response