Part 2: "Out of the Box" Dojo

Want to know what Dojo is and how it can help you with your javascript development? In this section we will walk through the process of putting Dojo to use with its collection of pre-packaged "Out of the Box" widgets that can get you using Dojo right away. We will focus on developing programs using existing dojo components. This section will not get into any advance features, as they are included in future chapters. If you are new to Dojo or even new to JavaScript, then this chapter is for you. If, however, you are a seasoned programmer, you can still find reading this section purposeful as it will provide a helpful overview to the Dojo toolkit.

The sample application is the familiar Hello World app however, it does introduce the main features of Dojo and will build the foundation for developing much more sophisticated web applications.

Thanks to Lance Duivenbode and Seth Fair for help in writing this chapter.

Development and Debugging Tips

This section talks about some of the tools available to help develop JavaScript programs. With the increasing popularity ofJavaScript there surely will be alot of changes in this space in a relatively short time. In this section you will find helpful tools that may or may not be part of Dojo.

Also remember to check the Dojo FAQs especially the Common Pitfalls section.

Debugging JavaScript

There are excellent tools to help write and debug Javascript - it isn't all about liberally using alert() any more!

IDEs

IDEs are available which support a wide range of web development activity, including editing Javascript and HTML files, deploying code to servers, and integration with existing features like source control. In addition, some include runtime tools and browser integration to assist in debugging (for example, myeclipse and ATF)

If you use one of the JavaScriptEditors that checks your syntax as you enter your code, you can be warned immediately of simple errors and save yourself a lot of time. Some Eclipse plugins even specifically support Dojo idioms by giving you tooltips for common Dojo functions and doing more complex analysis for errors (not just normal syntax checking).

Browser specific tools

Mozilla/Firefox

  • The Web Developer Toolbar is brilliant.
  • The Firebug extension is a must for debugging and inspecting html pages - dojo.debug can also be configured to output directly to Firebug's console. It contains a simple Javascript debugger too. just use dojo.require("dojo.debug.Firebug") in your pages.
  • Venkman is the mozilla javascript debugger - ugly and cantankerous, but it can be useful if you need to debug in FF. Note that in general the IE debugger is much better. Use the venkman port for FF1.5.
  • Live HTTP Headers is a good extension for debugging HTTP traffic (You may prefer to use the equivalent functionality that exists in the in Firebug extension).
  • JavaScript Shell - While it's not a debugger, I've found the JavaScript Shell to be a really great tool for analyzing problems, and even just exploring JavaScript libraries like dojo. Works best as a firefox bookmarklet, in which case you can open it in the context of any given page and invoke javascript functions yourself, evaluate expressions, redefine functions, etc.

Debugging on Firefox may need you to use the djConfig flag debugAtAllCosts (see further below for information). The debugAtAllCosts flag is sometimes necessary to locate exceptions or syntax errors. Even without the debugger, Mozilla and Firefox are unable to locate a line of code loaded by dojo.require() due to a flaw in the way eval() debugging hooks are implemented in Spidermonkey. Currently, the Javascript console will report all source references as the location of the eval() call itself (in the bootstrap code), but with an additional line offset equal to the offset in the corresponding *.js file.

Firefox Safe Mode

If you are having wierd problems with Firefox, it is often worthwhile running Firefox in safe mode.

This is because installed extensions can interfere with the DOM tree, CSS, or even with javascript. In Windows there is a shortcut to start Firefox in safe mode from within the Mozilla Firefox folder, from the Start button.

Internet Explorer

If you are using a debugger with IE, go to Tools | Options | Advanced and make sure that Disable Script Debugging is not ticked. Using debugAtAllCosts can also help significantly - read about it below.

Safari

The debugger is Drosera.

The Safari Developer FAQ has some general information about developing with Safari, as well as instructions on how to turn on a debug menu that allows showing a Javascript console.

There is a "dom inspector" type tool, but it requires using a nightly build of Safari.

debugAtAllCosts

debugAtAllCosts may have unobvious side-effects - you should only use it if you are actually debugging. If you hit problems with files not loading or __package__.js then check that you are using writeIncludes() correctly, and try removing this flag to ensure that the flag is not the issue.

You generally should not use a packaged build if you want to debug, because in a packaged build the majority of code will end up in your dojo.js file (and usually be obfuscated due to compression).

The easiest way to understand how it helps with debugging is to see it's effect within a debugger. For example within Visual Web Developer Express the image on the left is when using debugAtAllCosts and the RHS image is without debugAtAllCosts being used:

To use it needs one more line in your page. Here's how you might use it:

<script>

djConfig = {

isDebug: true,

debugAtAllCosts: true

};

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

<script>

// dojo includes here

dojo.require("dojo.myModule");

dojo.hostenv.writeIncludes(); // this is a new line

</script>





// ...

Once you've structured your code this way, if you open up your debugger, you will see all the constituent files listed and you can then set breakpoints. You may need to add in dojo.require() statements for files that you want the files to show, above the writeIncludes(). If you do not, then any javascript files that need loading after the call to writeIncludes().

You can see an example of using debugAtAllCosts with your own widgets within your own namespace in dojo/src/tests/widget/test_Custom_Widget_Debugging.html

How does debugAtAllCosts work?

When debugAtAllCosts is set to true, then dojo.require() does not actually include the package at that point. It only gets included in the page once you call dojo.hostenv.writeIncludes().

Normally when you dojo.require() a file that is not already loaded, it is fetched using using an xmlhttprequest, and loaded into your Javascript runtime environment using an eval() statement (each of the eval items in the RHS screenshot above is actually a js file). When the file is eval()'ed, dojo.require() calls will occur, and those then recursively load any further dependencies (those which are not already loaded).

When you set debugAtAllCosts to true, the file is still fetched using xmlhttprequest but it is not eval()'ed. Instead a regexp is used to find the dojo.require() dependencies, and required files may be fetched and searched recursively for dependencies. Each of the required javascript filenames is added into a list of pending files that need to be loaded (the list is in order so that dependent files are loaded in the correct order). When you then call dojo.writeIncludes(), inside the head of the document script tags are appended with src attributes set to the js files that need to be loaded. The script tags cause the files to be loaded by the browser: files loaded this way are understood by debuggers much better than when the files are eval()'ed.

What alternatives are there to debugAtAllCosts?

If you just need to debug one or two known files, then you can just include those specific files using script tags after dojo.js. e.g.

<script src="/dojo.js" type="text/javascript"></script>

<script src="/mine/myWidget.js" type="text/javascript"></script>

You cannot do this for files that are packaged into your dojo.js (Of course, using packaged files makes debugging hard in other ways too!).

Profiling

Javascript is slow and you want to speed it up?

Use a ProfilingJavascript tool to help you find the functions where all the time is spent, and optimise those routines.

Traffic analysis

A great many problems can be resolved by watching the traffic between the browser and the server. If you are having any problems with Ajax calls such as bind() or with js/html/css/jpg files not loading as you would expect, this is often the best way to diagnose them quickly. Also if you are having problems with required files not loading then this is a good starting point to find out why.

  • Fiddler is a fantastic HTTP header and content inspector for Windows. It understands HTTP and presents the information very clearly (once you get used to its slightly quirky interface). Well integrated with IE, but work s with any browser. With FF a useful extension to help use Fiddler is the Switch Proxy extension (scroll down that page to find it).
  • Ethereal is great for sniffing all kinds of network traffic.

How do I debug syntax errors? aka How can I find this syntax error in bootstrap?

Sometimes Dojo's error messages about syntax errors are really cryptic due to how dojo loads files via dojo.require(), however you can get a better message by simply directly including the js file with the [script] tag.

The debugAtAllCosts flag can also be used.

There's also a lint program that Brian has recommended.

You can also find the debug error message in the dojo source code and remove the corresponding try/catch statement so that when the error occurs you get a debugger breakpoint instead of a dojo debug message.

Javascript debugger statement

Javascript has a debugger keyword that forces a breakpoint to occur. Just insert debugger; and if you have a debugger for your browser, then it will stop at the debugger keyword.

This is especially useful when using Venkman, because otherwise it can be difficult to get Venkman into debugging mode (e.g. you try to click on a line of source and it puts in a [F] future breakpoint).

It also works with the Firebug extension for Firefox.

Debug Messages

You can debug the old fashioned way (print statements in the code). There are three functions for this:

  • dojo.debug - prints a message
  • dojo.debugShallow - prints all the members in an object
  • dojo.debugDeep - opens new window w/tree showing structure of an object

Debugging output:

  • FireBug object - this will print debugging output to the Firebug console
  • DebugConsole - will capture all your debug messages in a floating pane.

Alternately, in djConfig, you can specify which element they are appended to by

providing an id of that element: i.e.:

var djConfig = {

isDebug: true,

debugContainerId : "dojoDebug"

};

and have a div

<div id="dojoDebug"></div> Author: Carla

JavaScript Editors

Editors/IDEs

ATF (Eclipse)

Ajax Toolkit Framework is an incubator project within the Eclipse Web Tools Project. It is also a pluggable framework for other AJAX tools. It provides Javascript syntax checking, server deployment, Mozilla embedding, runtime tools such as XHR Monitor, and a debugger based on Mozilla Spidermonkey, JSD, and the Eclipse debug UI. Eclipse integration provides access to existing plugins like ant, subclipse for SVN, server development tools, etc. AJAX "Personalities" provide the potential for tighter integration with Dojo and other toolkits, although so far very little has been done in this area.

There's visual Javascript validation built into ATF. It includes both basic syntax validation and optionally Jslint validation for less obvious potential syntax problems. It works just like MS Word as-you-type spellchecking and Eclipse as-you-type Java validation - as you type if you make a syntax error (or just do something somewhat sloppy) you'll get a red or yellow squiggly under the warning/error and an explanation in the margin. A background task will run validation against all files and place markers in the code such that you can see errors across a project.



You can download and use ATF and its prerequisite Eclipse components (Eclipse SDK, WTP, EMF, GEF, JEM, xulrunner) and choose to use all of ATF or just install the "javascript" feature which implements this validation.



Note - you have to fetch and manually install jslint.js, Dojo and xulrunner due to Eclipse policies - make sure to read the ATF readme to get the full functionality of ATF.

JSEclipse

JSEclipse is a commercial Eclipse plugin which provides a rich Javascript editor with support for syntax validation, code completion and Dojo idioms.

MyEclipseIDE

To be written...

JS-Sourceror (Eclipse)

JS-Sourceror performs syntax checking and variable type and flow analysis on JavaScript files.

JavaScript plugin for jEdit

See http://skrul.com/blog/projects/javascript

It also does syntax checking, as well as scope checking and structure browsing.

Aptana

Aptana is an open-source, JavaScript-focused IDE, including code assist for Dojo. It works as a stand-alone app on Mac, Linux, or Windows, or as a plug-in for Eclipse.

Profiling JavaScript

Profiling is the term for looking at where time is spent by any Javascript code. If you have a problem with code taking too long, then it helps to use a profiling tool to diagnose exactly where all the time is being used.

When using some profiling tools you may need to use debugAtAllCosts and not a packaged version of Dojo (see DebuggingJavascript). Using debugAtAllCosts will enable the profiling tool to allocate time spent per function to the correct source file -- otherwise you will end up with the elapsed times being allocated to anonymous functions which will make it difficult for you to understand!

Profiling Tools

dojo.profile

dojo.profile is a package that implements timing primitives for recording how much time is spent in particular functions. To learn how to use it, the best resource is to search the tests directory and look at how it is used by various tests.

FireBug 1.0

Displays the time it took to load each file.

Venkman (for Firefox)

Free but a bit buggy to use. I have found it easiest to get into debugging mode with Venkman by using a debugger keyword in your sourcecode. Run the Venkman debugger, then run your code and it will stop at the breakpoint.

Venkman contains a profiling tool, although the reports are a bit difficult to use. It does work.

Tito web studio

It seems it does not work with Dojo. It modifies JavaScript, and obviously in some manner incompatible with Dojo.

Manually do it yourself

Get the time at the start and end of a routine, and calculate the difference. Not a great technique, because you have to make educated guesses as to where the inefficient areas are, and it may take quite a lot of work to home in on the problem area.



But it is easy to do if you are measuring a single function:

function() {

var startTime = new Date();

// do something here

dojo.debug("Total time: " + (new Date() - startTime));

}



Or another example of code to do this is on this page near the top under the heading "Measure your changes".

Getting Started

If you are new to Dojo or want a quick overview of the toolkit then take a look at the HelloWorld Tutorial. This tutorial describes step by step how to build a simple Dojo application. You will learn some basic concepts about widgets, events and how to connect to the server code. Each step builds on the previous until you have a working application. It takes about an hour to go through the tutorial.



Adding Dojo to Your Pages

Dojo offers many editions of its code base. At first, it might seem daunting to try to figure out exactly which one you need. To quickly dispel any worries, let me assure you that every single edition of dojo provides a fully functioning system. Whether you download one of our editions, or the full, uncompressed source code, you'll be able to perform any of the examples discussed in this book.

TODO: fold in information from the README

In order to use dojo in your HTML pages, you need three sections of code, in this order:

1. Flags

<script type="text/javascript">

djConfig = { isDebug: false };

</script>

The flags control various options of dojo; often developers will set isDebug to true in order to get debugging output on their page. (There are also some other flags related to debugging; see the Debugging section of the code for details.)

2. Include the dojo bootstrap

<script type="text/javascript" src="/path/to/dojo/dojo.js"></script>

This includes the bootstrap section of dojo, and if you are using a release build, then dojo.js will also include code for some of the dojo modules.

3. Define what resources you are using

<script type="text/javascript">

dojo.require("dojo.event.*");

dojo.require("dojo.io.*");

dojo.require("dojo.widget.*");

</script>

This section is much like java's "import" statement. You specify every resources that you are using in your code. However, note that widgets are a special case and don't need to be declared explicitly, assuming that (as is the case with the built-in dojo widgets), a manifest file defines which widget is in which resource file.

Pre-Packaged Builds

Even though Dojo is made up of many different packages, it's frequently used in very specific ways. Because of this, we've created special editions of Dojo aimed toward these users. A visit to dojo's download page will show you which editions are currently available, such as the Ajax and Widget edition.

An edition is very simple, really. The important file is dojo.js, which is created by merging the most frequently used packages and compressing the resulting code. This means that when you have a script tag that calls dojo.js, you're getting not just the basic Dojo codebase, but the additional functionality that is most pertinent to your specific use.

You might wonder why so much additional code comes in each edition. This is the full code base, and allows you to use functionality that is outside of your specific build. It means that even if you have a very specifically tailored edition of Dojo, you aren't limited to only using that featureset. If your site uses the event and I/O systems heavily, but one of your pages uses a widget, then you don't have to worry that your widget will break. This also means that any of the examples in this book will work no matter what edition you've downloaded.

Introducing Dojo Events

Events in JavaScript or Dojo based applications are essential to making applications work. Connecting an event handler (function) to an element or an object is one of the most common things you will do when developing applications using Dojo. Dojo provides a simple API for connecting events via the dojo.event.connect() function. One important thing to note here is that events can be mapped to any property or object or element. Using this API you can wire your user interfaces together or allow for your objects to communicate. The dojo.event.connnect() API does not require that the objects be Dojo based. In other words, you can use this API with your existing interfaces.

Here we connect the event handler, helloPressed, to the onClick property of the hello button element. When the button is clicked the funtion helloPressed will be called.
      function helloPressed(){
        alert('You pressed the button');
      }

      function init(){
        var helloButton = dojo.widget.byId('helloButton');
        dojo.event.connect(helloButton, 'onClick', 'helloPressed')
      }

It is also possible to use the Dojo event model to connect simple objects. To demonstrate, lets define a simple object with a couple of methods:

var exampleObj = {
    counter: 0,
    foo: function(){ 
        alert("foo");
        this.counter++;
    },
    bar: function(){
        alert("bar");
        this.counter++;
    }
};

So lets say that I want exampleObj.bar() to get called whenever exampleObj.foo() is called. We can set this up the same way that we do with DOM events:

dojo.event.connect(exampleObj, "foo", exampleObj, "bar");

Now calling foo() will also call bar(), thereby incrementing the counter twice and alerting "foo" and then "bar". Any caller that was counting on getting the return value from foo() won't be disappointed. The source method should behave just as it always has. On the other hand, since there's no explicit caller for bar(), it's return value will be lost since there's no obvious place to put it.

In either case, each time dojo.event.connect is called with the same arguments it will result in multiple connections. Later we will discuss strategies on how to guard against this.

Notice that dojo.event.connect takes a different number of arguments in the examples above. dojo.event.connect determines the types of positional arguments based on usage.

The Dojo event system allows you to connect to DOM elements or nodes or plain JavaScript objects. The API is sophisticated enough that it allows you to connect multiple listeners to a single object so you can have multiple actions as a result of a single event such as a mouse click. Of course there is an API to disconnect the listeners too. The Connecting the Pieces chapter describes the Dojo Event system in more detail.

Introduction to dojo.io.bind

At Dojo, we're committed to making DHTML applications usable, both for authors and for users, and with a lot of help from our friends, particularly Aaron Boodman and Mark Anderson, we have come up with solutions to the usability problems outlined above. We're providing it in a single, easy to use API and a package that requires only two files to function. The dojo.io package provides portable code for XMLHTTP and other, more complicated, transport mechanisms. Additionally, the "transports" that plug into it each provide their own logic to make each of them easier to use.

Most of the magic of the dojo.io package is exposed through the bind() method. dojo.io.bind() is a generic asynchronous request API that wraps multiple transport layers (queues of iframes, XMLHTTP, mod_pubsub, LivePage, etc.). Dojo attempts to pick the best available transport for the request at hand, and in the provided package file, only XMLHTTP will ever be chosen since no other transports are rolled in. The API accepts a single anonymous object with known attributes of that object acting as function arguments. To make a request that returns raw text from a URL, you would call bind() like this:

dojo.io.bind({

url: "http://foo.bar.com/sampleData.txt",

load: function(type, data, evt){ /*do something w/ the data */ },

mimetype: "text/plain"

});

That's all there is to it. You provide the location of the data you want to get and a callback function that you'd like to have called when you actually DO get the data. But what about if something goes wrong with the request? Just register an error handler too:

dojo.io.bind({

url: "http://foo.bar.com/sampleData.txt",

load: function(type, data, evt){ /*do something w/ the data */ },

error: function(type, error){ /*do something w/ the error*/ },

mimetype: "text/plain"

});

Errors and Timeouts

Regular web requests and Ajax requests with dojo.io.bind are much alike. Both use URL's and both use the HTTP protocol. But with browser requests, it is always clear to user when something goes wrong. You may get a 404 - Page Not ound, or a Server Unavailable, or at least something that says "Error". Ajax requests happen in the background, so when they error out the user won't know. Even worse, if the response never comes the browser may appear to lock up.

That's why it's extremely important to provide an error handler and a timeout handler with dojo.io.bind. You should consider these as critical as URL or the load function

At the very least, you should alert the user that something went wrong. Here's an example:

var kw = {

url: "/cgi-bin/timeout.cgi",

load: function(type, data, evt){

document.myForm.myBox.value = data;

dojo.byId("boxLoadTime").innerHTML = new Date();

},

error: function(type, data, evt){

alert("Holy Bomb Box, Batman! An error occurred: " + data);

},

timeoutSeconds: 2,

timeout: function(type, data, evt){

alert("I am tired of waiting.");

}

};

The error() function takes the same arguments that load() does. But unlike load(), the only useful parameter is data, which contains the error message.

The timeoutSeconds and timeout parameters should be used together. timeoutSeconds defaults to 0, which means "wait forever". (In other Ajax libraries, this is called a synchronous request). 0 is not desirable. Even if you expect the request will take a long time, you should set a high value here (e.g. 3600 = 1 hour), not 0. The timeout function takes the same arguments as error() and load(), but they are rarely consulted.

Hello Ajax World

So let's apply this to a trivial example. Suppose you have a text file on the web server with url my_message.txt.

Hello Ajax World!

You would like to load the file contents in an INPUT box without refreshing the page. Here's how:

<html>
<head>
<title>Insert title here</title>
<script type="text/javascript" src="/js/dojo/dojo.js"></script>
<script type="text/javascript">
    function loadRemotely(e) {
        var kw = {
            url:    "my_message.txt",
            load:    function(type, data, evt) { 
                        document.myForm.myBox.value = data; 
                        dojo.byId("boxLoadTime").innerHTML = new Date();
                    },
            method: "GET"
        };   
        dojo.io.bind(kw);
    }
    function initAjax() {
        dojo.event.connect(dojo.byId("loadIt"), "onclick", "loadRemotely");
    }
    dojo.addOnLoad(initAjax);
</script>
</head>
<body>
    Form loaded at:
    <script type="text/javascript">document.write(new Date());</script>
    

    <form name="myForm">
    <input type="button" id="loadIt" value="Click here to load value.">
    

    <input type="text" name="myBox" size="50" />
    Text loaded at: <span id="boxLoadTime">N/A</span>
    </form>
</body>
</html>

Click the button and the value in my_message.txt automatically loads into the box. The date and time stamps on the page prove it does not reload when the user clicks the button.

This demonstrates the bare minimum you need for dojo.io to connect with Ajax. At the very least, you need an object of type dojo.io.Request. In our examples, this is the "kw" variable. dojo.io.Request needs the following:

  • url is the URL containing content - usually generated on the server, and often using a database
  • load(type, data, evt) is the function called after the URL has been retrieved. This is an example of a callback function. It must have both parameters defined, although you don't need to read both of them. data is the most important, and contains the entire content retrieved from the URL. type is always "load". evt captures data about the load event.
  • method is either "GET" or "POST". GET is common - we'll see an example of submitting a formful of data later on. That will require a POST.

There are many more optional parameters, and we'll see these in later examples.

Then just call dojo.io.bind with the dojo.io.Request variable. Here, bind means "connect this page with that URL and let things happen."

Why do all that for some static text? The answer is ... you won't. The URL is going to be a server-side program which returns content - mostly XML (the "X" in AJAX), but it could be text, HTML, or even binary data.

Sending Form Data

The Url of dojo.io.Request may contain parameters, like so:

url:  'myprogram.php?firstname=Chicken&lastname=Little&key=111111'

There are two problems: (1) it's difficult to URL encode everything, (2) it doesn't allow for dynamic parameters. The above works fine for everyone named Chicken Little, but ...

It's easier and more flexible to send an entire form of data. And you can do that with the formNode parameter of dojo.io.Request.

<script>

var kw = {

url: "myprogram.php",

load: function(type, data, evt){

document.myForm.myBox.value = data;

},

error: function(type, data, evt){

alert("Holy Bomb Box, Batman! An error occurred: " + data);

},

timeoutSeconds: 2,

timeout: function(type, data, evt){

alert("I am tired of waiting.");

}

formNode: dojo.byId("myForm");

};

dojo.io.bind(kw);

</script>
<form id="myForm">

<input type="hidden" name="key" value="111111" />

<input type="text" name="firstname" length="50" />

<input type="text" name="lastname" length="50" />




<input type="text" name="myBox" length="50" />

</form>

Modules, Resources, and Widget Namespaces

Modules

Dojo's code is split into logical units called modules. These are much like packages in Java, except that in Dojo a module can contain both constructors (like classes in Java) and simple functions.

For example, the "dojo.html" module contains a number of functions, such as dojo.html.getContentBox(). The "dojo.dnd" module contains a number of constructors for things like HtmlDragObject etc.

Note the naming convention - functions start with a lowercase letter, and constructors (which are technically functions but act more like classes) start with a capital letter.

Modules could be called "namespaces", except for the fact that "namespaces" has a different (but related) meaning w.r.t. widgets.

Resources

In the simple case, a Dojo module is defined in a single JavaScript file. But sometimes, a single module is split into multiple files.

For example, the dojo.html module, although originally defined in a single file, was getting too big, so we split into multiple files. This is for performance reasons, so that the browser only downloads the code it needs.

Unfortunately this implementation detail is not transparent to the Dojo user. You have to know which file contains the functions you need, and then include that file explicitly.

Each of these files is called a resource.

The line:

dojo.require("dojo.html.extras")

will include the file src/html/extras.js, which in turn defines some of the functions (but not all the functions) in the dojo.html module.

A single JavaScript file never defines multiple modules, although often a single file will define multiple constructors. In Java this would be equivalent to defining two classes in the same file.

All of this complication is for performance reasons, trying to balance

  • not downloading more stuff than you need
  • not downloading too many tiny files


Setting up Require Statments

How do you know what resources to dojo.require()?

1. modules

First, find out what modules you are using. In this example we'll assume you are using dojo.lfx.html.

2. resources

By reviewin the API doc you can see that dojo.lfx.html is defined in two files:

  • src/lfx/html.js
  • src/lfx/extras.js

Depending on what functions you are using, you will either do

dojo.require("dojo.lfx.html");

or

dojo.require("dojo.lfx.html");

dojo.require("dojo.lfx.extras");

Wildcards

There is a wild card include, such as dojo.lfx.* . New users might be surprised to learn that this may not necessarily include everything under lfx. Rather, there is an __package__.js file that defines what is included with the wild card, and this may also depend on the environment in which Dojo is loaded. For example, a browser will likely load different modules than Dojo would when loaded with Rhino on the command line.



dojo.provide()

Each file defining a resource should have (exactly) one line at the top defining the name of the resource.



Example:

  dojo.provide("dojo.html.extras")
For historical reasons, the dojo.provide() call serves two functions:

  1. define the name of the resource (and register that the resource is loaded)
  2. make sure that the resource's module exists (ex: make sure that dojo.html exists), so that statements like "dojo.html.foo = ..." don't fail with an error about dojo.html not existing.

Widget Namespaces

Widgets are combined into groups called namespaces. All the widgets built into Dojo are in the "dojo" namespace, but someone else could write their own widgets and put them in a different namespace. For example, you could write your own button and checkbox widgets, and put them into an "acme" namespace. Then "acme:Button" would be your button, and would be unrelated to the button object built into dojo, called "dojo:Button".



Information on writing your own widgets occurs later in this book.





Widgets

When browsing through web sites and online applications, there are hundreds of widgets that come across your screen. Each button in your web browser is a widget. Each text entry box is a widget. We all know what a limited set of widgets that standard HTML provides: an input box, a button, a hyperlink.

Dojo widgets take an item like a text input box and adds functionality of a more user friendly object, like a graphical calendar to choose a date from. And it does this without breaking the original item on which the new functionality is built on.

The Widget Object

The first thing that you'll notice about widgets is that the are somewhat similar to a macro expansion, such as C's #define. Your source HTML is a simple

<button dojoType="Button" id="foo"> Click me </button>

and yet a pretty blue button shows up, and when you look at the generated DOM, it's a complicated tree of DOM nodes with a lot of absolute positioning and background images.

See?

But, that's not all there is. For each widget, besides the visible manifestation, there's also a pure javascript object that manages that generated DOM tree.

In the above case, the generated javascript object is called, unsuprisingly, "foo". You can get it by doing:

var myButton = dojo.widget.byId("foo");

Turning Plain HTML Into Widgets

A Dojo widget wraps around your HTML. It looks at how the HTML is organized, what type of tags have been specified, what attributes they have, which tags are children of what other tags. All of these different variables allow a versatility in how skeletons are laid out, in what tags they use, in how the widget chooses to interpret them.

More Than One Way to...

You can think of a widget as the final form that covers a skeleton. The top widget layer reflects the structure and functionality of the skeleton it sits on rather than covering it up.The simplest example of a skeleton is a single tag. A form input box, for example, is designed to simply accept a value.

<inputvalue="default">

But what happens when we want to help the user choose from an existing list of items? Enter the ComboBox widget.

<input dojoType="ComboBox" value="default">

As you can see, this is a functional skeleton. Not only is there an input box if the user does not have JavaScript enabled, but we can use the widget as part of a normal form. After all, we've only added on to it, we haven't changed the original purpose of the input element.

But this widget provides no data for the combo box to use.

<input dojoType="ComboBox" value="default" dataUrl="comboBoxData.js">

If you want to produce valid W3C HTML, you will have to use an alternative method to building your skeletons. The dojoType attribute is not recognized by W3C and its validation tool will complain about it being their. Below are two examples that do not use invalid attributes to build on your skeletons.

<input class="dojo-ComboBox" value="default" dataUrl="comboBoxData.js">
<dojo:ComboBox value="default" dataUrl="comboBoxData.js">

When there are certain attributes (dataUrl in this example), this widget will use that information to process the information to be contained in the combo box.

Sometimes you'll have skeletons defined in code and not even know it. In fact, many of the widgets provided by dojo assume that the underlying HTML is the same that would be encountered in every day life. Making this select element into a widget is as simple as adding the dojoType attribute.

<select dojoType ="combobox">

<option value="foo">foo</option>

<option value="bar">bar</option>

<option value="baz">baz</option>

<option value="thud">thud</option>

</select>

As you can see, you've just gained a whole lot of something for nothing. And, the data that will be used in the combo box is provided in a way that any web designer would understand.

TODO: this section needs to differentiate between ComboBox and Select.

Why Use Widgets?

You may ask yourself, "Why would I use wigets?" I honestly couldn't have answered this a few months ago, before finding Dojo anyway. The answer is really quite simple once you see how widgets improve the functionality and appearance of your web applications, without taking a long time to implement.

Enhanced User Experience

Widgets "enhance the user experience". In layman's terms, that means that you can design web pages that are easier for people use, more quickly understandable, less error-prone, and flashier than web pages in plain html.

Easier to use - the Select widget for example, will narrow down the list of available choices based on keystrokes the user enters. That makes it faster to use than a normal HTML select box.

More quickly understandable - a web page with tabs will let the user easily navigate between different sections, and helps to make clear all the different sections of code that are on one page.

Less error prone - validation widgets will immediately notify users when they have entered an incorrect value, and/or automatically correct the value.

Flashier - dojo's menu code will fade in / out menus, or use some other effect, rather than a plain appear/disappear that you get with pure CSS menus

Faster Development

Widgets make it easy for web developers to add enhanced functionality. Here's why:

No Javascript Required

Web designers are generally very good with HTML. The really good ones are usually so involved in design that they don't even bother with learning the extra stuff that comes along with its dynamic aspect.

For these kinds of users, specifying widgets via HTML is a great solution. Not only is markup useful for being able to design with a placeholder element laying in wait, but many of the widgets actually analyze what they've laid out and use them as if properties were passed to the JavaScript object.

A great example of this is the tree widget. All that the designer has to do is lay out an HTML list, assign some attributes and they can have things going without having to touch a bit of code.

No worrying required

Widgets solve a bunch of issues (like cross-browser support) behind the scenes, so you don't have to worry it. See the next section for more detail about that.