Using the Dojo Framework to Build Custom HTML Widgets | 3 | WebReference

Using the Dojo Framework to Build Custom HTML Widgets | 3

By Rob Gravelle


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".

Under the 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 -- The className will be used as a global name for a created constructor. When specified, the name is stored in the created prototype's declaredClass 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 named constructor.

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: