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
- Chrome
- Internet Explorer 9
ReferenceError: on is not defined
Uncaught ReferenceError: on is not defined
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
- Chrome
- Internet Explorer 9
TypeError: dom.byId is not a function
Uncaught TypeError: Object function has no method ‘byId’
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
- Chrome
- Internet Explorer 9
ReferenceError: require is not defined
Uncaught ReferenceError: require is not defined
‘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
- Chrome
- Internet Explorer 9*
Error: xhrFailed
GET incorrectPackage/myModule.js 404 (Not Found)
* 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
- Chrome
- Internet Explorer 9
TypeError: matchesTarget is undefined
Uncaught TypeError: Cannot call method ‘matches’ of undefined
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
- Chrome
- Internet Explorer 9
data.getElementsByTagName is not a function
XML
JSON*
TypeError: undefined method
XML
JSON*
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
- Chrome
- Internet Explorer 9
TypeError: document.musicPrefs is undefined
Uncaught TypeError: Cannot read property ‘other’ of undefined
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
- Chrome
- Internet Explorer 9*
GET http://localhost/dojo/invalid/path 404 Not Found
Failed to load resource: the server responded with a status of 404 (Not Found)
* 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
- Chrome
- Internet Explorer 9
SyntaxError: missing } after property list
Uncaught SyntaxError: Unexpected token ;
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
- Chrome
- Internet Explorer 9
defineAlreadyDefined
defineAlreadyDefined
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
- Chrome
- Internet Explorer 9
TypeError: myModule.init is not a function
Uncaught TypeError: Object 3 has no method ‘init’
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!