Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Introduction to the Dojo toolkit, Part 1: Setup, core, and widgets

Object-oriented JavaScript programming for Java developers

  • Print
  • Feedback

Page 6 of 6

Dojo modules

As your client code grows, it gets harder to keep all the functions and global variables from using the same names and wrecking one another. To solve this problem, Dojo introduces the concept of modules. Modules, similar to Java packages, allow you to divide the client-side code into different namespaces.

Our Hello World application uses modules. Everytime you call dojo.require(), Dojo loads one .js file into its own namespace. For example, when we invoke dojo.require("dijit.form.Button"), Dojo looks for a dijit/form/Button.js file under the Dojo root and loads it. Note that dojo.require() cannot load your code into different namespaces. It's the developer's responsibility to use namespaces in the code when creating modules. For example, the developer of dijit.form.Button took care of namespacing the code correctly. The Dojo framework code is divided into three namespaces -- dojo, dijit, and dojox -- that correspond to the three namespaces under the Dojo root. One module can represent either one class or a set of functions. For example, the dojo.string module represents a set of functions.

Working with modules

In the preceding section we developed the Worker class hierarchy by developing all the script code in index.html. But now we want to use the Worker class on multiple pages, so we will externalize Worker in a separate module by following these steps:

  1. Create a custom/javaworld directory under the Dojo root, which is the WebContent/js folder in our case. It is always a good idea to keep your code in separate directory.
  2. Create the WebContent/js/custom/javaworld/Worker.js file.
  3. Move your definition of the Worker, ITWorker, Musician, and PartTimeMusician classes to the Worker.js file. Add dojo.provide("custom.javaworld.Worker") at the top of Worker.js file:

    dojo.provide("custom.javaworld.Worker");
    dojo.declare("custom.javaworld.Worker",null,
    //Rest of the code to declare Worker, Musician, ITWorker and PartTimeMusician classes
    

    Each Dojo JavaScript source file must have at least one dojo.provide() call at the top of the file, corresponding to the file name. For example, our sample dojoroot/custom/javaworld/Worker.js file should have dojo.provide("custom.javaworld.Worker") at the top. When the browser loads Worker.js, the dojo.provide() call registers that it has been loaded.
  4. Once the Worker class definition is moved to its own module, you must make this change in index.html to use it:

    dojo.require("custom.javaworld.Worker");
    var johnDoe = new custom.javaworld.PartTimeMusician("John","Doe");
    

    The call to dojo.require("custom.javaworld.Worker") loads the module from the appropriate URI. If it can't find the .js file for the module, it throws an exception.

Package dependency

We've moved all four classes into one .js file, but it's always a good idea to create a separate module and separate namespace for each of the modules. Let's change our sample code so that Worker, ITWorker, Musician, and PartTimeMusician are loaded into different modules:

  1. Create ITWorker.js, Musician.js, and PartTimeMusician.js files under the WebContent/js/custom/javaworld folder.
  2. Move each class definition within its own .js file. A problem is that the ITworker class has a dependency on the Worker class, and PartTimeITworker has a dependency on ITWorker and Musician. A module can import code that it depends on using a dojo.require() call. The definition of PartTimeMusician should look like this:

    dojo.provide("custom.javaworld.PartTimeMusician");
    dojo.require("custom.javaworld.ITWorker");
    dojo.require("custom.javaworld.Musician");
    dojo.declare("custom.javaworld.PartTimeMusician",[custom.javaworld.ITWorker,custom.javaworld.Musician],{
    

    As you can see, the PartTimeMusician class is declaring that it has dependency on the ITWorker class and the Musician class by making two dojo.require() calls. Similarly, ITWorker will declare its dependency on Worker by making a dojo.require() call.
  3. Once your PartTimeMusician class is ready, you can use it in the index.html file:

    dojo.require("custom.javaworld.PartTimeMusician");
    var johnDoe = new custom.javaworld.PartTimeMusician("John","Doe");
    

    As you can see, we are making only one dojo.require() call to include the PartTimeMusican class. Dojo will take care of loading the dependencies of the PartTimeMusican class and will make sure that each resource is loaded only once.

Deploy the latest version of the sample Web application in Apache Tomcat and try accessing it in a browser. If you look into the Firebug console, you will notice that Dojo has loaded Worker.js, Musician.js, and ITWorker.js in addition to PartTimeMusician.js.

Using external directories

In the sample code so far, we've created the custom folder under same root as that of rest of the Dojo code. The problem with this approach is that it can muck up the Dojo root directory. If you keep your development separate from Dojo itself, source control is easier to deal with. Follow these steps to use an external directory instead:

  1. Move the custom directory from under WebContent/js to the WebContent directory.
  2. Change index.html to register the custom folder name:

    dojo.registerModulePath("mycode","../../custom");
        dojo.require("mycode.javaworld.PartTimeMusician");
    

    The registerModulePath() function is used to map the directory name to the module name. We want to register a module name of custom, which is equal to the /WebContent/custom directory. The second argument of registerModulePath should be the path of the custom directory relative to the Dojo directory.

If your custom code is divided into multiple directories, you can make multiple calls to registerModulePath(). You can also use modulePath's djConfig variable to map a module name to a directory name.

Conclusion to Part 1

Unlike other JavaScript frameworks, Dojo doesn't focus on only one specific part of JavaScript programming. Instead it is more of a one-stop solution for most JavaScript-related infrastructure. In the second half of this article, you'll explore some of Dojo's more advanced features, such as its simplified XMLHttpRequest, which allows you to query and manipulate your document's DOM structure. You'll also learn about Dojo's event model, which enables you to attach event handlers to DOM events.

About the author

Sunil Patil is a Java Enterprise/Portlet developer working for Ascendant Technology in San Francisco, California. He is the author of Java Portlets 101 (SourceBeat, April 2007) and has written numerous articles published by O'Reilly Media, IBM developerworks, and JavaWorld. Sunil was a member of IBM's WebSphere Portal Server development team for three years and is actively involved in the Pluto community. In addition to being an IBM Certified WebSphere Portal Server Application Developer for both v5.0 and v5.1, he is a Sun Microsystems Certified Java Programmer, a Web component developer, and a business component developer. You can read Sunil's blog at http://wpcertification.blogspot.com.

Read more about Enterprise Java in JavaWorld's Enterprise Java section.

  • Print
  • Feedback

Resources

More from JavaWorld