Dojo is the Open Source, portable JavaScript toolkit that lets you build interactive modules quickly, animate transitions, and construct Ajax requests with ease. We think Dojo is the most powerful and easiest to use Ajax and DHTML toolkit on the planet.
Here's what you'll need to know to get started with Dojo.
Supported Browsers
Dojo supports a wide variety of browsers:
Downloading and Installing Dojo
Dojo Editions
Dojo offers several different editions for download, such as Ajax and I/O. When you download an edition of Dojo, you get a pre-built "profile" that includes multiple Dojo JavaScript files rolled into a single dojo.js file. Each edition packages different features into dojo.js. The dojo.js file lets you access all features that are part of the profile (and retrieve all the library functionality in one HTTP request). And dojo.js is the only thing you need to include into your application or page to use the capabilities built into the Dojo profiles that you downloaded. Awesome!
All editions provide the entire Dojo library within dojo/src. Any features that are not built into the dojo.js package can be dynamically loaded at runtime through dojo.require.
Dojo on the AOL CDN
The Ajax edition of Dojo is currently available on the AOL Content Distribution Network (CDN), at:
http://o.aolcdn.com/iamalpha/.resource/jssdk/dojo-0.2.2/dojo.js
You can import this one script file into your HTML page and begin using Dojo immediately without having to download or install anything. This URL is the standard place for AOL apps to load Dojo. It puts the dojo.js file closer to the end user than serving it from your own Web server. Also, the more applications that refer to this location, the better the chances of it already being in the browser cache.
NOTE: Currently, dynamic loading of Dojo features does not work from the CDN (due to a security issue with accessing script files from two different domains). This issue is known and is actively being worked on. If you need to use functionality that is not built in to the Ajax profile (such as drag and drop, or XML parsing), you'll need to refer to your own instance of Dojo until this is resolved.
Custom Builds
If you don't want to use an existing edition, you can create a custom build of dojo.js that includes only the functionality you need.To create a custom build, you'll need to download the full Dojo source tree, create a new profile under dojo/buildscripts/profiles, and then run the ant build task. For more information, refer to "Building Dojo" in dojo/README.
A custom build can reduce the download size of your application, but you should balance this benefit against using a shared Dojo instance from a well-known URL such as the AOL CDN. A shared instance could require your app to download some functionality that it doesn't need or use, and it increases the chances of the script file already being in use in the browser cache.
Release Builds
The code inside dojo.js is compressed using Dojo's script Compressor. This removes most of the white space and makes the script hard to read. But if you want to read the Dojo code, there is an uncompressed version at dojo/dojo.js.uncompressed.js. Of course, you should always import the compressed version into your HTML page. You can, and should, use Dojo's Compressor on your own application code for release builds. You can combine multiple script files into one file, and strip comments and white space. This will make for a significantly smaller and faster download (fewer bytes and fewer HTTP requests).
For more information on the Compressor, refer to Dojo Compressor Overview.
REMINDER: Make sure that all your code resources (script, HTML, and CSS) are served gzipped with the GNU compression program. Also, you should gzip all dynamic server responses using mod_gzip, or a similar Apache Web server external extension module.
Lazy Loading
While a certain subset of Dojo functionality is baked into each profile build, all of Dojo's capabilities are reachable using dojo.require statements (or by including source files manually). Modules of Dojo functionality are defined by the package system. It associates one or more physical JavaScript files with a logical target.
There are usually several targets for a given package, allowing you to include only specific targets, or to include the entire module (using the dot star notation). The Dojo package system looks a lot like Java's. For instance, if you've downloaded the I/O Edition, but want to start using the event system, you can use the dynamic loading system to pull it in at runtime:
dojo.require("dojo.event.*");
Or you can load a specific target:
dojo.require("dojo.event.browser");
Since dynamic loading is synchronous, a call to dojo.require will block until all the required code has been loaded. This means you can start using dynamically imported features right after the require statement, without having to wait for a callback. And, any dependencies that a required package might have are resolved automatically by Dojo. For example, Dojo will make sure that any code that the required package needs is also dynamically loaded.
The package system is driven by a manifest file called __package__.js that lives within the dojo/src directories. You can check this file to see what targets are defined for a given package.
Importing library features dynamically will be slightly slower than if the feature was included within the dojo.js file, but unless you are including many large packages, the difference should be minimal. If you are importing many packages dynamically you should consider creating a custom build of Dojo.
For more information on Dojo packages, refer to Getting Started With Packaging.
Getting Started
Ok, here we go.
First, you should import the dojo.js file into your HTML page. Dojo can be configured by creating a global object named djConfig before the Dojo library is included.
Dojo has built-in support for a minimal debugging console. You can specify a DIV to use for output using djConfig and then style the DIV to put it where you want (for example, using position and overflow).
Set djConfig.isDebug to true so that Dojo will log any internal error message to the console. You can also output your own debugging messages through dojo.debug().
NOTE: Dojo has a rich logging feature in dojo.log. By default, this API won't display log messages to the console. It seems most folks are simply using dojo.debug() instead.
<div id=dojoDebugOutput></div>
<script type="text/javascript">
var djConfig = {
isDebug: true,
debugContainerId : "dojoDebugOutput",
};
</script>
<script type="text/javascript" src="http://o.aolcdn.com/iamalpha/.resource/jssdk/dojo-0.2.2/dojo.js"></script>
<script type="text/javascript">
var onDojoLoad = function() {
dojo.debug("Ready to run my script...");
// do your thing...
}
dojo.addOnLoad(onDojoLoad);
</script>
Dojo Modules
This section is a tour of the Dojo packages, showing what is available and pointing out some of the most useful and interesting features.
Dojo
dojo.require – ensures that the Dojo module has been loaded. dojo.byId – shorthand for document.getElementById. dojo.debug – outputs a string to the debug console. dojo.addOnLoad – callback when Dojo has finished loading. dojo.debugShallow – writes all properties of an object to the debug console. dojo.inherits – provides "classic" inheritence for JavaScript classes (see dojo.lang.extend, below).dojo.render
dojo.render.html.ie – describes the browser capabilities of the current hosting environment. dojo.render.os.win – describes the operating system capabilities of the current hosting environment.dojo.lang
dojo.lang.hitch – runs a function in a given context; can be used to preserve context:
hitch( foo, "bar" ); // runs foo.bar() in the scope of foo
hitch(foo, myFunction); // runs myFunction in the scope of foo
When working with member functions, it's very useful to be able to associate a callback function with the scope of the member function, for example:
MyClass.prototype.myFunction = function() {
setInterval(function() { // 'this' pointer not correct }, 1000);
setInterval(dojo.lang.hitch(this, function() {
// 'this' pointer works
}, 1000);
}
dojo.lang.setTimeout – improves on window.setTimeout. Can pass arguments to the timer function, and set its context (this pointer):
setTimeout (Object context, function func, number delay[, arg1[, ...]]);
setTimeout (function func, number delay[, arg1[, ...]]);
dojo.lang.extend – extends a class by copying properties of a provided object to the class prototype. A compact syntax for adding methods and values to a class.
Original syntax:
foo = function() {};
foo.prototype.name = "foo";
foo.prototype.bar = function() { alert("bar"); };
With dojo.lang.extend:
dojo.lang.extend(foo, { name: "foo", bar: function() { alert("bar"); } };
Here's an example of subclassing an existing Dojo class. I create a new class called SliderDragSource, inherit functionality from dojo.dnd.HtmlDragSource, and then override the onDragStart method:
SliderDragSource = function(node, type, slider) {
this.slider = slider;
}
dojo.inherits(SliderDragSource, dojo.dnd.HtmlDragSource);
dojo.lang.extend( SliderDragSource, { onDragStart: function() {} } );
dojo.io
dojo.io covers many different transport layers (such as XMLHTTP and iframes) and provides a uniform and simple interface through the dojo.io.bind method. Here's a sample server call over XMLHTTP that provides JSON data in response:
var bindArgs = {
url: "http://path/to/myServerAPI.js",
mimetype: "text/json",
transport: "XMLHTTPTransport",
error: function(type, error, httpObj) {
// handle error
},
load: function(type, data, httpObj) {
// data object has JSON response
}
};
dojo.io.bind(bindArgs);
This code will call the server API at URL using the XMLHTTP transport. On success, Dojo calls the load handler back, and passes the JSON server response, resurrected as a JavaScript object. On error, Dojo calls the error handler. The httpObj is passed back so that HTTP error codes can be retrieved through httpObj.status.
For more information on the dojo.io.bind API, refer to this Dojo article.
dojo.event
dojo.event is a very powerful package. It gives you an easy way to add DOM event handlers, but also provides the ability to treat *any* function call as an event, and to create a loosely coupled publish and subscribe mechanism.
For DOM events, dojo.event.connect provides a uniform interface to setting events to the browser's event object. It resolves underlying bugs on different browsers and simplifies common tasks such as:
evt.preventDefault and evt.stopPropagation work correctly across browsers. Allows callbacks on instance methods. Avoids the IE memory leak.Here's the basic syntax:
var handlerNode = dojo.byId("handler");
function handleOnClick(evt){
// evt parameter contains 'fixed' cross-browser event object
}
dojo.event.connect(handlerNode, "onclick", "handleOnClick");
Or, using an anonymous function:
var handlerNode = dojo.byId("handler");
dojo.event.connect(handlerNode, "onclick", function(evt){
// ...
});
DOM event handlers can be hard to write elegantly when they are within instance methods, since, when the callback occurs, the 'this' pointer refers to the DOM element that generated the event, not the context of the instance method. For example:
MyClass.prototype.addClickHandler = function() {
this.myMethod(); // 'this' pointer points to instance of MyClass
dojo.byId("button").onclick = function(evt) {
// 'this' pointer refers to "button" node, not MyClass instance
}
}
dojo.event.connect provides an elegant solution:
MyClass.prototype.addClickHandler = function() {
this.myMethod(); // 'this' pointer points to instance of MyClass
dojo.event.connect(dojo.byId("button"), "onclick", this, function(evt) {
this.myOtherMethod(); // works now
});
}
The same function can also be used to add a callback function whenever another function gets called. The last line of the example below will call obj.bar whenever obj.foo is called.
var obj = {
foo: function(){
alert("foo");
},
bar: function(){
alert("bar");
}
};
dojo.event.connect(obj, "foo", obj, "bar");
Finally, the event package contains a publish and subscribe feature using named "topics." This allows anonymous communication between components such as between a model and view in an MVC architecture. To connect the functions foo and bar above using topics, we would write this:
// set up our publisher
dojo.event.topic.registerPublisher("/example", obj, "foo");
// and at some point later, register our listener
dojo.event.topic.subscribe("/example", obj, "bar");
For more information about the DOM event handler and how to use dojo.event in your JavaScript, refer to this Dojo article.
dojo.dom
dojo.dom – provides utility methods to manipulate DOM nodes, over and above what is provided by the browser DOMAPI:
dojo.dom.moveChildren – moves a set of nodes from one parent to another. dojo.dom.removeChildren – remove all child nodes from a node. dojo.dom.isDescendantOf – identifies if one node a descendent of another. dojo.dom.getFirstAncestorsByTag – looks for an ancestor node of tag type (for example. "img"). dojo.dom.insertBefore – inserts new DOM child node. dojo.dom.insertAtPosition – inserts new DOM child node.dojo.style
dojo.style provides numerous functions for working with a node's style object, fixing many underlying bugs on various browsers. All code that performs pixel-wise measurement and manipulation of DOM nodes should prefer these clearly named cover methods over the browser's built-in functions: dojo.style.getInnerWidth dojo.style.getAbsolutePosition dojo.style.setOpacitydojo.html
dojo.html – provides utility functions for the browser environment:
More Dojo Modules
There are many other useful modules within Dojo that we have not covered, such as:
dojo.string Drag and drop high-level API Path animation through dojo.animation Visual effects such as fades and wipes using dojo.fx XML manipulation through dojo.xml ~50 prebuilt UI widgets such as FloatingPane, RichText, and SortableTable.Download Size
It's critical that a JavaScript library be a very small download. We still have a large percentage of users on dialup, where 4 kB equals one second of user wait time. Dojo's JavaScript Compressor and custom build system are both a testament to needing to send as few bytes as possible to the browser.
Here are the code sizes for various build targets in the 0.2.2 version of Dojo (all numbers refer to gzipped code size).
dojo.lang). 17.6kB – I/O edition (adds XMLHTTP, string, DOM). 35kB – Ajax edition (includes I/O Edition and adds event, style, DOM, html, and a rich set of basic features, but no widgets or drag and drop functionality). 60kB – Kitchen Sink edition (includes the entire library).The Ajax build is representative of the functionality required for a moderately complex DHTML application. 35 kB is a substantial download, but the functionality provided will substantially reduce the amount of application-specific code (and, of course, development time).
Licensing
The license for Dojo is designed to be straightforward and to allow the library to be widely used with no General Public License (GPL) type stickiness.
For more information on Dojo's software licensing history and policy, refer to this Dojo article.
Recommended Development Tools
Here are the development tools that we recommend:
Learning More About Dojo
Here are things you can do to learn more about Dojo:
dojo-interest mailing list. To learn how to use a library feature, look at the unit test files located in the dojo/tests directory of the dojo source tree. Grep the source a lot, read dojo.js.uncompressed.js. NOTE: The grep command searches one or more input files for lines containing a match to a specified pattern.