Top Ten Getting-Started-With-Dojo Tips

You heard good things about the Dojo library. What is the absolute minimum you need to know in order to start coding effectively with Dojo?

Discalimer: This post does not claim that Dojo is better than JQuery nor the converse. Each library has its strengths. My personal view is that JQuery offers a well designed programming model (the $("selector") thing is ingenious). On the other hand, Dojo currently offers a more extensive set of standard widgets.


#1: Importing Modules

dojo.xd.js is the basic module. Once you imported it into your page via <script src=".."> you can use dojo.require('fully.qualified.name') to import additional Dojo modules.

<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
</script>
</head>
<body/>
</html>


#2: addOnLoad()

addOnLoad() lets you register a function that will be called once page loading is finished. This is Dojo's cross-browser-compatible way to hook the onLoad event.

<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>

<script type="text/javascript">
dojo.addOnLoad(function() { alert("hi"); })
</script>
</head>
<body/>
</html>


#3: Widget creation -- Programmatic Style

There are two ways to create widgets: Programmatically (shown here) and declaratively (see tip #5). Either way, you must first import the corresponding module via a require() call.

In the programmatic you create a widget by calling its constructors, which typically takes two parameters:

  • options: a plain Javascript object specifying widget-specific options

  • id: The ID of a DOM node which will host this new widget


In the example below, a button widget is created via new dijit.form.Button({}, "click-me-button"), which means: no options; ID of hosting element is "click-me-button".


<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.addOnLoad(function() {
var button = new dijit.form.Button({}, "click-me-button");
button.attr("label", "Click Me");
});
</script>
<link rel="stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"/>
</head>
<body class="claro">
<div id="click-me-button"/>
</body>
</html>


#4: Overriding a Widget's Methods

Any method defined in the constructor's first parameter will be attached to the newly created widget, thereby overriding an existing method with the same name. The code below overrides the onClick method of the Button widget.

Initial values for the widget's properties can be specified in a similar manner: { label: "Click me" }


<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.addOnLoad(function() {
new dijit.form.Button({
onClick: function() { alert("Thank you!"); },
label: "Click me!"
}, "click-me-button");
});
</script>
<link rel="stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"/>
</head>
<body class="claro">
<div id="click-me-button"/>
</body>
</html>


#5: Widget creation -- Declarative Style

The declarative style lets you define widget by using HTML markup. To enable this you MUST specify djConfig="parseOnLoad: true" at the <script src="dojo.xd.js"> element.

You can then use a dojoType="dijit.form.Button" HTML-attribute to tell the Dojo parser to create a button widget that will be hosted by the enclosing HTML element.

A nested <script type="dojo/method" event="onClick" args="evt"> element will define a callback method for the onClick event. A nested <script type="dojo/connect"> element will define code that will be executed when the widget is created.


<html>
<head>
<script djConfig="parseOnLoad: true" type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
</script>

<link rel="stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"/>

</head>
<body class="claro">
<div dojoType="dijit.form.Button">
<script type="dojo/connect">
this.attr("label", "Click Me!");
</script>
<script type="dojo/method" event="onClick" args="evt">
alert("Thank you!");
</script>
</div>
</body>
</html>


#6: Defining widget variables -- Declarative Style

If you add a jsId="myButton" attribute to an HTML element that defines a Dojo widget (i.e. has a dojoType attribute) the Dojo parser will assign the widget to a global variable named myButton.

This allows programmatic access to a declaratively-defined widget.


<html>
<head>
<script djConfig="parseOnLoad: true" type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.addOnLoad(function() {
alert("Press OK to change style");
myButton.attr("style", "color:red; font-weight:bold;");
});
</script>

<link rel="stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"/>

</head>
<body class="claro">
<div dojoType="dijit.form.Button" jsId="myButton">
A simple button
</div>
</body>
</html>


#7: Obtaining the associated DOM node

Widgets and DOM nodes are distinct objects. In order to get the DOM node associated with a widget, use the widget's .domNode property.

                
<html>
<head>
<script djConfig="parseOnLoad: true" type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.addOnLoad(function() {
myButton.domNode.innerHTML = myButton.domNode.innerHTML.bold();
});
</script>

<link rel="stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"/>

</head>

<body class="claro">
<div dojoType="dijit.form.Button" jsId="myButton">
A simple button
</div>
</body>
</html>


#8: Looking up a DOM node

dojo.byId("someId") is Dojo's cross-browser-compatible way to obtain a DOM node by its ID.


<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.addOnLoad(function() {
dojo.byId("some.div").innerHTML = "found it!";
});
</script>
</head>
<body>
<div id="some.div"/>
</body>
</html>


#9: The Widget -> Model -> Store Pattern

Sophisticated Dojo Widgets, such as the Tree or the DataGrid widgets rely on the following structure:

The widget observes a model which observes a data store which maintains the actual data.

There are several (predefined) models that can work with each widget. The Tree widget, for example, can work with either a TreeStoreModel or a ForestStoreModel. These models can work with stores such as ItemFileWriteStore or ItemFileReadStore.


<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require( "dijit.Tree" );

function initPage() {
var store = new dojo.data.ItemFileWriteStore({ data:
{
identifier: 'id',
label: 'name',
items: [
{ id: 1, name: 'Star Wars Saga', root: true,
children:[{_reference: 2}, {_reference: 3}, {_reference: 4}] },
{ id: 2, name: 'Star Wars' },
{ id: 3, name: 'The Empire Strikes Back' },
{ id: 4, name: 'Return of the Jedi' },
]
}
});

var treeModel = new dijit.tree.ForestStoreModel({
store: store,
query: { 'root': true }
});

var widget = new dijit.Tree({model: treeModel, showRoot: false }, "div-tree")
}

dojo.addOnLoad(initPage);
</script>
<link rel="stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"/>
</head>

<body class="claro">
<div id="div-tree"></div>
</body>
</html>


#10: Change the Widget's Content by Mutating its Data Store

When you're dealing with Widget-Model-Store setup and you want to change the content displayed by the widget, the correct way to do it is to change the data store object. These changes will be propagated along the observation chain and will eventually be reflected at the UI.

Obviously, the store object must support mutations. Read-only stores (such as: ItemFileReadStore) will not work for you, here.

The code below invokes store.deleteItem() when the "Delete 'Return of the Jedi'" button is clicked. The associated Tree widget is automagically updated.


<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require( "dijit.Tree" );

function initPage() {
var store = new dojo.data.ItemFileWriteStore({ data:
{
identifier: 'id',
label: 'name',
items: [
{ id: 1, name: 'Star Wars Saga', root: true,
children:[{_reference: 2}, {_reference: 3}, {_reference: 4}] },
{ id: 2, name: 'Star Wars' },
{ id: 3, name: 'The Empire Strikes Back' },
{ id: 4, name: 'Return of the Jedi' },
]
}
});

var treeModel = new dijit.tree.ForestStoreModel({
store: store,
query: { 'root': true }
});

var widget = new dijit.Tree({model: treeModel, showRoot: false }, "div-tree");

new dijit.form.Button({
label: "Delete 'Return of the Jedi'",
onClick: function() {
store.fetchItemByIdentity({ identity: 4, onItem: function(item) {
store.deleteItem(item);
} });
}
}, "div-button");
}

dojo.addOnLoad(initPage);
</script>
<link rel="stylesheet" type="text/css"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"/>
</head>

<body class="claro">
<div id="div-button"></div>
<div id="div-tree"></div>
</body>
</html>

6 comments :: Top Ten Getting-Started-With-Dojo Tips

  1. I have been working with Dojo for a while now, and already finished reading several books about Dojo. I would like to say that this article is one of the best. Everything is presented clear and simple. Well done!

  2. Hi Maman,
    Hi please clear my Doubt. Suppose if I don’t want include Google URL (script, css location) in my project source code. What are the steps I have to do?
    java script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js">
    href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"

    Thanks
    Jagadeesh G

  3. I suggest you go to http://dojotoolkit.org/download/ which provides several download options. It offers three CDN options (Google, AOL, Yandex), and also packaged zip/js files which you can place on you web server.

  4. I promise you i have been searching the net for the past 2 weeks in figuring out a simple way to build a tree with simple add and delete. I was impressed to see that this one really taught me. But you have not added the code for adding a node.

    Please add up and i am waiting for your humble reply to know how to add a node as the first child of the parent.

    with regards Anand

  5. I tried to add a new node but failed

    new dijit.form.Button({
    label: "ADD Nodei'",
    onClick: function() {
    store.fetchItemByIdentity({ identity: 1, onItem: function(item) {
    var myNewItem = {id: 5, name: "Fill this country name"};
    //store.newItem(myNewItem);
    store.newItem(myNewItem,{parent:item, attribute:[]});
    store.save();

    } });
    }
    }, "AddButton");

  6. I have been searching code for invoking callback when a deletion of node happens in dojo store. it is possible to have a callback?

Post a Comment