Web developers are drawn to Dojo for its incredible collection of widgets, which can make even the most boring Web form come alive with surprisingly little effort. Dojo's out-of-the-box Dijit and Dojox controls are good enough to please all but the most discerning of users, but for those of you who refuse to fit your pages to conform to a pre-defined widget design, the Dojo Framework can also be extended to write your own widgets. It's a fairly painless way to combine several controls to enhance your business processes.
As with all Dojo widgets, you have the option of creating yours declaratively or programmatically. In today's article, we'll be taking the declarative route. Our widget will display financial information on some common commodities such as gold and crude oil. It will include a small graph as well as a list of details relating to that commodity.
Directory Structure for Widget Components
Under your Web server's root directory, you'll need to create some
folders to store the widget components. Most developers prefer to put their
custom widgets in a folder that is not under the Dojo
root because that can
be updated as new versions of the Dojo library are released. The standard place
for them is in a sibling directory called, you guessed it, "widgets
".
widgets
folder, you should have three or even four more subdirectories,
depending on how modularized you want the various components to be. The subfolders,
which very much mimic the usual Web server structure, include CSS
, images
, scripts
,
and templates
. The page that will contain the widget(s) is called stockWidget.html
and it resides in the root directory:
Figure 1: Folder Structure for Dojo Widgets
Note that I have left the widget script in the StockInfo.html
page
for the purposes of development.
The Dojo Template File
Dojo Templates is one of the foremost reasons that Web developers
love the Dojo library, and it's easy to see why when you think about it. There
wouldn't be much point to building a reusable component if the HTML was buried
in the containing page, now would there? It makes sense to store the markup within
a template because it's really what represents an instance of your widget. Here
is what the markup for the StockInfo.html
file:
Widget Initialization Code
Although we are using the declarative style of widget creation,
we still need to include some code to initialize startup properties. Among the code
is the global djConfig
object. I prefer to declare it in code rather than as
a tag attribute because I find it easier to work with different data types that
HTML attributes don't support (they deal only with strings). For instance, the
modulePaths
is an object literal that may contain paths for a number of modules.
In our project, we have two modules called templates and images. I always turn
on the isDebug
flag in development, but then I remove it before rolling out
to production. The parseOnLoad
attribute tells Dojo to parse the HTML code for
controls to convert into widgets. In most cases, it's easier to let Dojo take
care of that job, even for custom widgets.
A second script appends the Dojo libraries. You can either use a hosted version of the script or serve it from your server, as I did.
The third and last script contains our widget code. The dojo.provide()
method is an integral part of Dojo's module system and its loader. It tells
the loader that a module has been provided for the given name. It also creates
a JavaScript object for the name. That will allow us to declare our widget a
little later. We also need to import the dojo.cache
, Dijit._Widget
and digit._Templated
modules using dojo.require()
.
Here is all the code that we've discussed thus far:
Widget Declaration
Dojo's dojo.declare()
method provides functionality that simulates
Java's class system. It emulates OO constructs such as prototypal inheritance,
classical inheritance, and private members.
It accepts up to three arguments:
className (null|String)
: The optional name of the class to declare -- TheclassName
will be used as a global name for a created constructor. When specified, the name is stored in the created prototype'sdeclaredClass
property. If you don't specify it, the class is assumed to be anonymous.superclass (null|Object|Object[])
:This parameter can be null for no base class, an object for one base class, or an array of objects for multiple inheritance.props (Object)
: An object whose properties are copied (mixed in) to the created prototype after all other inheritance has been solved -- You can add an instance-initialization function by making it a property namedconstructor
.
The following code declares the StockInfo widget:
Class Member Properties
The template is specified in the widget attribute templateString
,
and points to some HTML within a single root node, which may include special
attributes on the tags as well as possibly substitution variables. It can either
be specified as a literal string such as <div>hello world</div>
or pulled in from a file using dojo.cache()
. In addition to making your code
more modular, it's also a lot less cumbersome to write HTML in a template file
than as a string literal in JavaScript. The dojo.cache()
method accepts a string
argument that specifies the path to the file that contains the HTML using the
templates modulePath
that we declared in the djConfig
variable. It will load
the contents of the file via a synchronous XMLHttpRequest (XHR) call. The second
argument contains any additional path information as well as the file name.
The remaining properties store information that will be displayed
in the widget. They include the name, ticker symbol, price, and price change.
There is also an imagePath
, but we don't need to specify it just yet: