Current Articles | RSS Feed
Dojo is a powerful user interface framework used for building interactive web applications. Though it bundles a great deal of functionality, you can also extend it by creating custom components. Let's see how.
Dojo provides a collection of JavaScript utilities that solve many problems faced by the web developers. The software comprises a number of modules: Dojo base, Dojo core, Dijit, and DojoX. Dojo base is the foundation of the Dojo Toolkit, and includes mainly DOM, Ajax, and animation APIs. Dojo core provides a set of components built on top of the Dojo base that includes drag-and-drop APIs, localization and internationalization components, and data store APIs. Dijit is a comprehensive widget system that provides all core UI components and utilities. DojoX provides a set of advanced components that includes graphics libraries, mobile components, and other experimental components.
Although Dojo offers a comprehensive set of rich components for the web developers, sometimes a business needs a higher level of abstraction for more business-oriented reusable components. Such components might be a composite of two or more Dojo components, or an extension to an existing component to support a new feature that's not supported directly by the framework.
Fortunately, Dojo offers a neat mechanism for creating custom components, as you'll see here. The example code here is tested with both Dojo 1.4 and 1.7; it should work fine with all future pre-Dojo 2 releases.
In this lesson, you will create a "hello world" custom Dojo component as shown in the figure below:
Creating a custom Dojo component involves five basic steps:
Organizing the component structure from the beginning helps a lot in updating and maintaining the Dojo component later on. One of the suggested structures uses a parent folder (I usually call mine "custom"), under which are three items:
One of the best practices for creating Dojo widgets is to separate the widget template from the widget class. The following listing shows the template of our custom component:
<div> Hello <span dojoAttachPoint="nameNode" class="highlightedName"> ${sayHelloTo} </span></div>
The component template should have one and only one parent tag. Here it is the <div> tag. The dojoAttachPoint attribute represents a reference to the DOM element for every component instance. In other words, the Dojo attach point is a clean mechanism for referring to the HTML elements of the component without needing to use the IDs of the HTML elements. The main purpose of the Dojo attach point is to avoid a collision if you have more than one instance of the Dojo component in the same page. The ${attribute} expression refers to the value of a defined component attribute. In our case, ${sayHelloTo} refers to the value of the sayHelloTo attribute of our custom Dojo component.
dojoAttachPoint
${attribute}
${sayHelloTo}
sayHelloTo
To create the widget class, I extend two main Dojo classes:
dijit._Widget
dijit._WidgetBase
dijit._Templated
dijit._TemplatedMixin
Let's look at the details of the widget class code:
dojo.provide("custom.helloWorldWidget");dojo.require("dijit._Templated");dojo.require("dijit._Widget");dojo.require("dijit.Tooltip");dojo.declare("custom.helloWorldWidget", [ dijit._Widget, dijit._Templated ],{ templatePath: dojo.moduleUrl("custom","templates/helloWorldWidget.html"), /* Define your component custom attributes here ... */ sayHelloTo: "", constructor: function() { // add here anything that will be executed in the widget initialization. }, postCreate: function() { // add here anything that will be executed after the DOM is loaded and ready. // For example, adding events on the dojo attach points is suitable here. var localSayHelloTo = this.sayHelloTo; // Show a Dojo tooltip on the user name node. new dijit.Tooltip({ connectId: [this.nameNode], label: "The selected name is: " + this.sayHelloTo }); // Attach an onclick event on the user name node. dojo.connect(this.nameNode, "onclick", function (event) { alert("The selected name is: " + localSayHelloTo); }); }});
The dojo.provide is a core part of the Dojo module system. The dojo.provide("custom.helloWorldWidget") statement informs the Dojo loader that a specific module has been loaded with the name "custom.helloWorldWidget". The consumers of this component should use the dojo.require("custom.helloWorldWidget") statement to load the component.
dojo.provide
dojo.provide("custom.helloWorldWidget")
"custom.helloWorldWidget"
dojo.require("custom.helloWorldWidget")
Dojo calls the widget constructor when the widget is instantiated. You can add any initialization code for the widget in its constructor.
Dojo calls the postCreate method when the DOM elements are loaded and ready for actions. The postCreate method is a good place for attaching events to the DOM elements of the component. In our example, an onclick event is attached to the nameNode (the attach point I define in the template), and displays the sayHelloTo attribute in an alert message.
postCreate
onclick
nameNode
A Dojo tooltip is also attached to nameNode. It will appear when a user makes a mouseover action on the attach point.
In every widget class you have to define the component attributes. In this case, we have only one attribute defined in the widget class: the (sayHelloTo) attribute.
The templatePath property defines the path of the HTML template file of the widget class. Based on the HTML template file, the dijit._Templated class creates the widget's DOM tree.
templatePath
Once we have a widget template and a widget class, we can style the component. For this example I created a file called custom.css that includes the style class of the component. As you can see from the listing below, it is a very simple style.
.highlightedName { font: italic bold 30px serif;}
To test the component, you have to register the helloWorldWidget module path in an HTML page using the dojo.registerModulePath Dojo API. This API takes two arguments: the module name and the module path. You must also load the helloWorldWidget module using the dojo.require("custom.helloWorldWidget") Dojo API as shown in the listing below.
helloWorldWidget
dojo.registerModulePath
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html> <head> <script src="dojo/dojo/dojo.js" djConfig="parseOnLoad: true"> </script> <link href="dojo/custom/css/custom.css" rel="stylesheet" type="text/css"/> <script type="text/javascript"> dojo.registerModulePath("helloWorldWidget","custom/helloWorldWidget"); dojo.require("dojo.parser"); dojo.require("custom.helloWorldWidget"); </script> <link rel="stylesheet" type="text/css" href="dojo/dijit/themes/tundra/tundra.css"/> </head> <body class="tundra"> <span dojoType="custom.helloWorldWidget" sayHelloTo="Hazem Saleh"></span> </body></html>
Finally, we use the component by creating a span element whose Dojo type is custom.helloWorldWidget, with a specific value in the sayHelloTo attribute. Using the djConfig="parseOnLoad: true" statement, the Dojo parser works after the DOM elements are loaded and the custom.helloWorldWidget component is instantiated and executed.
custom.helloWorldWidget
djConfig="parseOnLoad: true"
You can download the full component code from Wazi.
Allowed tags: <a> link, <b> bold, <i> italics