Debugging JavaScript can be a tedious and frustrating chore. To compound the already difficult task of debugging, browser vendors each have their own style of error messaging, some of which are confusing, cryptic, or downright misleading to the untrained eye. Through the delivery of our Dojo workshops, we’ve observed a number of common mistakes that are easy to fix once you decipher the error message. Take some time to familiarize yourself with the following common errors that appear when working with Dojo, their symptoms, and their solutions. With this knowledge, writing manageable code is not only possible, but a lot less cryptic.

Issue: Missing Parameter

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • ReferenceError: on is not defined

  • Chrome
  • Uncaught ReferenceError: on is not defined

  • Internet Explorer 9
  • The value of the property ‘on’ is null or undefined, not a Function object

Possible Cause

You are missing a module parameter in the callback function of require. As you can see in the example, we list dojo/on as a dependency, but forget to specify it as a parameter to our callback function. As such, whenever we attempt to reference it, it fails because it is undefined.

	require(["dojo/dom", "dojo/on"], function (dom) {
		on(dom.byId("button"), "click", function (e) {
			console.log("My button was clicked!");
		});
	});

Solution

Ensure you specify a callback parameter for each module that you’re including to which you will need locally scoped access. If you’re getting a ReferenceError or “not a Function”, chances are, you missed a parameter.

Issue: Callback Parameter Mismatch

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • TypeError: dom.byId is not a function

  • Chrome
  • Uncaught TypeError: Object function has no method ‘byId’

  • Internet Explorer 9
  • Object doesn’t support property or method ‘byId’

Possible Cause

The callback parameter order does not match the dependency order. As you can see in the code, we require our dependencies in the order of dojo/dom and then dojo/on; however, in our callback, we have them in the order of dojo/on and then dojo/dom. Dojo does not magically know that dojo/on is mapped to the local variable on; it simply maps the returned factory function from dojo/on to the local variable specified in the given order. As written, the example makes our on variable actually reference the dojo/dom module and vice versa.

	require(["dojo/dom", "dojo/on"], function (on, dom) {
		on(dom.byId("button"), "click", function (e) {
			console.log("My button was clicked!");
		});
	});

Solution

Make sure your callback parameters match up to the order of your dependency list in require or define.

Issue: Wrong dojo path

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • ReferenceError: require is not defined

  • Chrome
  • Uncaught ReferenceError: require is not defined

  • Internet Explorer 9
  • ‘require’ is undefined

Possible Cause

The path to your dojo.js file is incorrect.

		<script src="incorrect/path/to/dojo.js"></script>

Solution

Ensure the URL in the src of your script is the correct path to dojo.js

Issue: Incorrect package path

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • Error: xhrFailed

  • Chrome
  • GET incorrectPackage/myModule.js 404 (Not Found)

  • Internet Explorer 9*
  • * IE9 will not show an error in the JavaScript console, your code will simply just fail. In order to see the 404, you have to go to the “Network” tab and click “Start Capturing”.

    * The Dojo Loader will also pass the number 3 to the callback in place of the module. 3 is the Dojo AMD loader code for attempting to load a non-module.

Possible Cause

The package you are referencing has an incorrect path. This can happen when using an incorrect MID (module identifier) as a dependency or when a package is configured incorrectly in your dojoConfig.

	require(["incorrectPackagePath/myModule"], function (myModule) {
		myModule.doSomething();
	});
	var dojoConfig = {
	    packages: [{
	        name: "myPackage",
	        location: "incorrect/path/to/myPackage"
	    }]
	};

Solution

Ensure you are using the correct paths to your packages. If you are getting a non-module error, this is the most common reason why.

Issue: Forgot dojo/query with Event Delegation

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • TypeError: matchesTarget is undefined

  • Chrome
  • Uncaught TypeError: Cannot call method ‘matches’ of undefined

  • Internet Explorer 9
  • Unable to get value of the property ‘matches’: object is null or undefined

Possible Cause

Using event delegation with dojo/on and forgetting to pull in dojo/query. To keep dojo/on as lightweight as possible, it does not automatically pull in dojo/query. Because of this, it does not have the capability to perform event delegation by default.

	require(["dojo/on"], function (on) {
		on(document.getElementById("myContainer"), "button:click", function (e) {
			console.log("A button was clicked!");
		});
	});

Solution

Ensure that you pull in dojo/query when you need to use event delegation with dojo/on.

Issue: Forgot handleAs for dojo/request

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • data.getElementsByTagName is not a function

    XML

    JSON*

  • Chrome
  • TypeError: undefined method

    XML

    JSON*

  • Internet Explorer 9
  • TypeError: Object doesn’t support property or method ‘getElementsByTagName’

    XML

    JSON

    * Notice how the data is parsed as a string, which makes the data[0] return as the first letter in that string, instead of the first element in what would be an array

Possible Cause

You have forgotten to set the handleAs property for dojo/request. When you do this, whatever value is returned is passed to the Deferred.resolve as plain text. This can cause issues if you’re expecting the data to be a JSON object or an XML document.

	require(["dojo/request"], function (request) {
		request("test.xml").then(function (data) {
			console.log(data.getElementsByTagName("name"));
		});
	});
	require(["dojo/request"], function (request) {
		request("states.json").then(function (states) {
			console.log("The first state object is", states[0]);
		});
	});

Solution

Ensure you use the handleAs property of the options object when using dojo/request.

Issue: Loop Bound Events

What you are experiencing

Events that fire all have the same value, or point to the same event handler.

Possible Cause

You used a loop to bind event handlers, and the final value in the loop is being referenced by the event handlers due to JavaScript’s closures. This will cause the same value to be referenced by all event handlers that were bound in the loop.

	require(["dojo/on"], function (on) {
		for (var i = 0, list = document.getElementById("list"), item; i < 5; i++) {
			item = document.createElement("li");
			item.innerHTML = "List item #" + i;
			on(item, "click", function () {
				alert(i);
			});
			list.appendChild(item);
		}
	});

How to fix it

You can create an event handler factory, or iterate over the items to add handlers using a forEach.

	function createHandler(value) {
		return function () {
			alert(value);
		};
	}
	require(["dojo/on"], function (on) {
		for (var i = 0, list = document.getElementById("list"), item; i < 5; i++) {
			item = document.createElement("li");
			item.innerHTML = "List item #" + i;
			on(item, "click", createHandler);
			item.onclick = createHandler(i);
			list.appendChild(item);
		}
	});

If you’re iterating over items, you can use dojo/_base/array.forEach

	require(["dojo/_base/array", "dojo/on"], function (arrayUtil, on) {
		var list = document.getElementById("list"),
			myArray = [0, 1, 2, 3, 4],
			item;

		arrayUtil.forEach(myArray, function (value) {
			item = document.createElement("li");
			item.innerHTML = "List item #" + value;
			on(item, "click", function () {
				alert(value);
			});
			list.appendChild(item);
		});
	});

You can use event delegation.

	require(["dojo/on", "dojo/query"], function (on) {
		on(document.getElementById("myContainer"), "button:click", function (e) {
			console.log("I was clicked!", e.target);
		});
	});

Issue: Forgot to Call startup

What you are experiencing

A Dijit does not appear to initialize fully.

Possible Cause

You forgot to call startup on the Dijit.

		<div id="container"></div>
	require(["dijit/layout/BorderContainer", "dijit/layout/ContentPane"], function (BorderContainer, ContentPane) {
		var container = new BorderContainer({
			design: "sidebar",
			gutters: true,
			liveSplitters: true
		}, "container"),
		leftPane = new ContentPane({
			splitter: true,
			region: "left",
			innerHTML: "Left Pane"
		}),
		centerPane = new ContentPane({
			splitter: true,
			region: "center",
			innerHTML: "Center Pane"
		});
		
		container.addChild(leftPane);
		container.addChild(centerPane);
	});

What it looks like

Without startup

With startup

Solution

Ensure you’re calling startup on widgets that are created programmatically. This is especially true for layout widgets.

Issue: Forgot dojo/domReady!

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • TypeError: document.musicPrefs is undefined

  • Chrome
  • Uncaught TypeError: Cannot read property ‘other’ of undefined

  • Internet Explorer 9
  • Unable to get value of the property ‘other’: object is null or undefined

Possible Cause

You have forgotten to use dojo/domReady!. dojo/domReady! waits until the DOM is ready to be manipulated before the require callback is executed.

	<script>
		document.musicPrefs.other.value = "Afrobeat";
	</script>
	<form name="musicPrefs">
		<input type="text" name="other" />
	</form>

Solution

If you need to interact with the DOM, use dojo/domReady! to ensure it’s completely loaded before your code executes on it.

Issue: Forgot Theme CSS Class Name

What you are experiencing

Your widgets look unstyled.

What it looks like without class name

What it looks like with class name

Possible Cause

You have forgotten to put a theme class name on body tag. This class is necessary on the body tag because of the way that the CSS rules are set up.

	<body>
		<button>Click me!</button>
	</body>

Solution

Ensure you add the class name ("claro", "tundra", etc) of the theme to the body tag. This class is necessary on the body tag because of the way that Dijit’s CSS rules are written.

Issue: Failed Resource Loading

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • GET http://localhost/dojo/invalid/path 404 Not Found

  • Chrome
  • Failed to load resource: the server responded with a status of 404 (Not Found)

  • Internet Explorer 9*
  • * IE9 will not show an error in the JavaScript console, your code will simply just fail. In order to see the 404, you have to go to the “Network” tab and click “Start Capturing”.

Possible Cause

Failed to load a resource via request. This can happen if the file is missing or if the URL is wrong. If you’re using dojo/request/registry, you may have a provider set up incorrectly.

	require(["dojo/request"], function (request) {
		request("invalid/path");
	});

Solution

Ensure your requests are pointing to the right URL. If you’re using dojo/request/registry, ensure that your provider is set up properly.

Issue: Load from the local File System

What you’re likely to see in your debugging environment

  • Chrome
  • XMLHttpRequest cannot load file:///D:/xampp/htdocs/dojo/test.xml. Origin null is not allowed by Access-Control-Allow-Origin.

Possible Cause

Loaded file from file system and not web server.

Solution

Ensure you are loading a page using the web server (http:// or https://) and not the file system (file:///)

Issue: Trailing comma

What you’re likely to see in your debugging environment

  • IE7 and before
  • Expected identifier, string or number

Possible Cause

Trailing comma in object literal. This is typically only an issue with IE7 and before, but is not valid, and should be avoided.

	var user = {
		name: "matt",
		email: "matt@email.com",
	};

Solution

Ensure you do not have trailing commas in your object literals.

Issue: Semicolon in Object Literal

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • SyntaxError: missing } after property list

  • Chrome
  • Uncaught SyntaxError: Unexpected token ;

  • Internet Explorer 9
  • Expected ‘}’

Possible Cause

Used ‘;’ instead of ‘,’ in object literal.

	var user = {
		name: "matt";
		email: "matt@email.com"
	};

Solution

Ensure that you use a comma between properties in object literals.

Issue: define Already Defined

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • defineAlreadyDefined

  • Chrome
  • defineAlreadyDefined

  • Internet Explorer 9
  • defineAlreadyDefined

Possible Cause

Including Dojo twice.

	    <script src="dojo.js"></script>
	    <script src="dojo.js"></script>

Solution

Ensure you are including Dojo only once.

Issue: Non-module module

What you’re likely to see in your debugging environment

  • Firefox + Firebug
  • TypeError: myModule.init is not a function

  • Chrome
  • Uncaught TypeError: Object 3 has no method ‘init’

  • Internet Explorer 9
  • Object doesn’t support property or method ‘init’

Possible Cause

You used require instead of define in your module definition. This will cause the module to be returned to your callback as “3”, which is the Dojo loader error code for non-module.

	// Inside of your module
	require(["dojo/on"], function (on) {
	    return {
	        init: function () {
				on(this.buttonNode, "click", function () {
					this.submitForm();
				});
			}
	    };
	});

Solution

Ensure you are using define in your module definitions.

Conclusion

Troubleshooting some JavaScript and dojo errors can be tedious and frustrating, but knowing these common errors will help alleviate some of that stress. There are also tools, such as JSHint that can help you lint your code and provide a quick set of eyes to catch some of the errors that were outlined here. Also, learning how to use Firebug or the Developer Console can also help shave time off of your development and debugging process.

Our team thinks this list should become a living document of common error messages so, please submit suggestions in the comments and we’ll incorporate them into this project in the future!