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 Modulesdojo.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 StyleThere 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 MethodsAny 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 StyleThe 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 StyleIf 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 nodeWidgets 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 nodedojo.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 PatternSophisticated 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 StoreWhen 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>