Dojo: An Introduction

Introduction

Dojo is a very interesting javascript toolkit, and has backings from numerous big players. This is an introductory article for some basic understanding of Dojo. An example speaks a thousand words. We will first start off with a basic page with a button.

index.html
<html>
  <body>
    <button>
      Test
    </button>
  </body>
</html>

Output Test

Adding Dojo

The previous page renders a simple button. Now, let's apply some Dojo on it.

index.html
<html>
  <head>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js" 
      djConfig="parseOnLoad: true"></script>
    <script type="text/javascript">
      dojo.require("dijit.form.Button");
      function call_function() {
        alert("Button was clicked.");
      }
    </script>
  </head>
  <body>
    <button dojoType="dijit.form.Button" onclick="call_function">
      Test
    </button>
  </body>
</html>

Output Test

Whoa, we have actually inserted a lot of things there! Clicking on the button triggers an alert box, which says Button was clicked. Now let's go through the code and discuss each feature by itself.

Initial Inspection

The first line of interest is actually the following:

  <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js" 
    djConfig="parseOnLoad: true"></script>

There are actually 3 ways to start using Dojo.

  1. Use Dojo from AOL's Content Distribution Network (CDN).

  2. Download Dojo and throw it into your web directory.

  3. Perform a custom build.

In this article, we will be using the CDN approach. Therefore the script src is pointed to http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js.

There is an additional parameter, djConfig in the script tag. We will come back to that in a bit.

As noticed, we defined a javascript function, which simply triggers an alert.

function call_function() {
  alert("Button was clicked.");
}

We will come back to the rest of the javascript in a bit as well, along with the djConfig.

<button dojoType="dijit.form.Button" onclick="call_function">
  Test
</button>

As noticed, there is a dojoType attribute defined. We have injected a Dojo widget, known as a Dijit, into the button. Dojo ships with a wide variety of ready-to-use widgets.

But these attributes are not part of the HTML specifications! So what magic has happened here?

The Dojo Magic: Declarative Dijits

Now we are back to the djConfig. Remember the value parseOnLoad: true? That is Dojo Magic!

When we defined that attribute, it tells Dojo to perform parsing on the HTML page it is included in. With each tag that defines dojoType, Dojo will actually create the specified widget based on that tag! Therefore it is essential that the attribute be defined, so that Dojo actually creates widget out of the page 'declaratively'.

To prove the point, we could remove the djConfig attribute. Now the button will no longer trigger the onclick function anymore!

Using Dojo Dijits: dojo.require

The other part of the magic happen with the dojo.require.

dojo.require("dijit.form.Button");

What this line does is to tell Dojo that we would like to use the Button Dijit. Without this line, the button would not be able to turn into a Dijit.

Dojo: A Modularized Toolkit

Dojo is actually a highly modularized toolkit. The core Dojo include is very small, with just a few core functions.

To use additional Dijits and other functionalities, you had to include it via dojo.require. What it does in the background, is actually to perform a HTTP Request to the server where Dojo was loaded from. From there, it will locate the specified module you had requested to be included, and stream it back to the page. The page will then introduce the newly downloaded modules to the page, ready to be use.

A Detailed Inspection on the output

If you have Firebug installed, or a similar DOM inspection tool, you could inspect the new DOM of the page. We will also list it down below, the DOM output of the page from FireBug with FireFox.

<div dojoattachevent="onclick:_onButtonClick,onmouseenter:_onMouse,onmouseleave:_onMouse,onmousedown:_onMouse"
  class="dijit dijitLeft dijitInline dijitButton dijitButton"  widgetid="dijit_form_Button_0">
  <div class="dijitRight">
    <button waistate="labelledby-dijit_form_Button_0_label" wairole="button" type="button"
      dojoattachpoint="focusNode,titleNode" class="dijitStretch dijitButtonNode dijitButtonContents"
      role="wairole:button" labelledby="dijit_form_Button_0_label" id="dijit_form_Button_0" tabindex="0"
      valuenow="" disabled="false">
      <span dojoattachpoint="iconNode" class="dijitInline">
        <span class="dijitToggleButtonIconChar">✓</span>
      </span>
      <span dojoattachpoint="containerNode" id="dijit_form_Button_0_label" class="dijitButtonText">
        Test
      </span>
    </button>
  </div>
</div>

Whoa! What just happened there? Where did all those things come from!

Dijits Are Widgets That Need Placeholders

We have to revisit our concept of widgets and placeholders. A widget is a ui component, to be displayed on the page. In order to place it on the page, we need to put it in a placeholder.

<button dojoType="dijit.form.Button" onclick="call_function">
  Test
</button>

The above actually defines a placeholder on the page. You basically say, you want the Button widget to be placed on this tag.

A widget does not necessary has to conform to the placeholder tag it is on. In fact, you could replace the above placeholder with the following.

<div dojoType="dijit.form.Button" onclick="call_function">
  Test
</div>

Test

And you would still have a Button Widget! But does that mean that we should not use the Button tag there? Absolutely not! Using the Button tag helps to build code clarity! Try to use the HTML tag that reflects most closely to the Dijit you will be using!

But still, where did all those output come from?

Dijits Are Templates

Each Dijit has a HTML template bound to it. Whenever Dojo injects Dijit into the page, it parses the tag, creates the Dijit, and pass any Dijit specific attributes to the Dijit itself. With the attributes, Dijit will load the bound template, and create the DOM nodes from the template.

A Detailed Inspection on the output II

Looking through the output, we would notice two id attributes. Dojo automatically defines id attribute and widgetid attribute. An id attribute can be looked up using document.getElementById (or dojo.byId), while a widgetid can be looked up using dijit.byId.

What About The Id I defined?

Let's try to insert a new id attribute to the Button tag.

<button dojoType="dijit.form.Button" id="test" onclick="call_function">
  Test
</button>

The new output is as follow.

<div dojoattachevent="onclick:_onButtonClick,onmouseenter:_onMouse,onmouseleave:_onMouse,onmousedown:_onMouse"
  class="dijit dijitLeft dijitInline dijitButton dijitButton"  widgetid="test">
  <div class="dijitRight">
    <button waistate="labelledby-dijit_form_Button_0_label" wairole="button" type="button"
      dojoattachpoint="focusNode,titleNode" class="dijitStretch dijitButtonNode dijitButtonContents"
      role="wairole:button" labelledby="dijit_form_Button_0_label" id="test" tabindex="0"
      valuenow="" disabled="false">
      <span dojoattachpoint="iconNode" class="dijitInline">
        <span class="dijitToggleButtonIconChar">✓</span>
      </span>
      <span dojoattachpoint="containerNode" id="dijit_form_Button_0_label" class="dijitButtonText">
        Test
      </span>
    </button>
  </div>
</div>

As noticed, the id attribute is now test, while the widgetid is now test as well.

widgetid And id

Now, what is the difference between an id and a widgetid?

An id works as it used to work, locating a DOM node.

A widget id, however, allows you to locate a created Dijit on the page.

But as you see, Dijit really inserts a lot more template into your original placeholder, and as such, you really should avoid using id to locate and modify anymore DOM properties.

For example, what if you had assumed that you could simply replace the text of your orginal button with the following code?

document.getElementById('test').innerHTML = "oh no!";

Putting that into the call_function, you would notice that the output, after clicking the button, becomes this!

<div dojoattachevent="onclick:_onButtonClick,onmouseenter:_onMouse,onmouseleave:_onMouse,onmousedown:_onMouse"
  class="dijit dijitLeft dijitInline dijitButton dijitButton"  widgetid="test">
  <div class="dijitRight">
    <button waistate="labelledby-dijit_form_Button_0_label" wairole="button" type="button"
      dojoattachpoint="focusNode,titleNode" class="dijitStretch dijitButtonNode dijitButtonContents"
      role="wairole:button" labelledby="dijit_form_Button_0_label" id="test" tabindex="0"
      valuenow="" disabled="false">
      oh no!
    </button>
  </div>
</div>

Let's just stick to widgetid, shall we?

If, however, you really need to get a particular DOM node, you could try to conform to the following approach.

<button dojoType="dijit.form.Button" id="test" onclick="call_function">
  <span class="test">Test</span>
</button>

And now, instead of setting the innerHTML directly, we do the following.

dojo.query('.test', document.getElementById('test'))[0].innerHTML = "oh no!";

Trying that out, we managed to just change the right node!

Sidetrack: dojo.query

Most javascript frameworks out there allow you to perform CSS style selectors to locate nodes. We no longer are restricted to locating nodes using only id.

Using CSS style selectors based on CSS class names, you are in fact, trying to play very nice with a lot of web frameworks out there. There are numerous frameworks out there who might modify an id attribute, or insert one of their own, thus making you wonder why your javascripts did not work properly. It is a debug nightmare!

dojo.query allows you to use css style selectors to locate DOM nodes. It returns a NodeList, which is an array of DOM nodes located. Thus, we used the [0] to indicate we want the first node located.

Themes

Another important basic feature I would like to touch on is themes. Themes is a way to style all the basic Dijits Dojo provides, providing a new look and feel of the Dijits.

Dojo provide three themes:

  • a11y

  • soria

  • tundra

Of course, there is also the basic theme, or rather styling, you get if you simply include the dojo css.

To apply a particular theme, you have to include the css required for that theme, as well as specify the theme in the enclosing tag.

<style type="text/css">
  @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
  @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/soria/soria.css";
  @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css";
</style>
...
<p class="tundra">
  ...
</p>

Themes rely on the workings of css. With a container specifying the named theme as the class, all contained widgets would have that theme applied. It can be more clearly explained with an example of a style in the css file.

.tundra .dijitToolbar { padding-bottom: 1px; }

As noticed, all toolbars (toolbars have the dijitToolbar class applied to them in the template) enclosed in a tundra themed container would have the above style applied.

Below are the examples of three kind of stylings.

tundra Test

a11y Test

soria Test

You will also notice that mouse over/hover styles are different for each themed button too!

Conclusion

This is really a very basic introductory article, designed to explain the very basics of Dojo.

I will follow up with another article, building up on the introductory knowledge we gained here.

References

The Dojo Toolkit: http://dojotoolkit.org

The Book of Dojo: http://dojotoolkit.org/book/dojo-book-0-9-0

Quick Installation: http://dojotoolkit.org/book/dojo-book-0-9/part-1-life-dojo/quick-installation

Hello World - Dojo for the Attention-Impaired: http://dojotoolkit.org/book/dojo-book-0-9/hello-world-tutorial

The Widget Life-cycle: http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/writing-your-own-widget-class/widget-life-cycl

Selecting DOM Nodes with dojo.query: http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/selecting-dom-nodes-dojo-query

Themes and Design: http://dojotoolkit.org/book/dojo-book-0-9/part-2-dijit/themes-and-design