Dissecting Dijit

The Dojo Toolkit is now an official release and we’re talking about new and changed features. In my previous post, I demonstrated Dijit’s brand new ability to construct widgets in markup. Now we’ll return to the more familiar Dijit Widget and see the culmination of the previous Dojo Toolkit betas.

Let’s start with a bare bones HTML document that includes the Dojo Core, a widget require statement, and a div to hang our widget. dojo.parser is here to parse any widgets in the HTML, and parseOnLoad=true enables automated widget parsing. An addOnLoad attachment ensures script execution only after the DOM is ready:





	

Here’s an example of, arguably, the simplest widget possible:

dojo.declare(
	"Simple",
	[dijit._Widget], {
		postCreate: function(){
			this.domNode.innerHTML = "Simple Widget"
        }
    }
);

So what is dojo.declare, anyway? Entire articles on dojo.declare define it in great detail. In essence, it builds a constructor that we can later turn into an object. The previous object just happened to be a widget that displays HTML. In fact, if you did this:

dojo.declare(
	"Simple",
	null,
	{ }
);

var obj = new Simple();

Here you would have created a JavaScript object, albeit with special Dojo goodness, like inheritance and extension syntactic sugar. For you Java guys, it’s a PODO or “Plain Old Dojo Object”. I was thinking of calling it a Definition Of a Dojo Object, but I digress.

So dojo.declare boils down to its class name (“Simple”), and any classes it may be extending. Our widget is extending the dijit._Widget class (the super-simple example used “null”, meaning it didn’t extend any classes). Our Simple widget is then followed by a mixed-in object of properties and methods which is where postCreate resides.

Notice we’re not using namespaces here. You may have seen the “acme.widget.Thinger” Dojo demos. It’s not explicitly required, but in doing it this way, we’ve created our widget constructor in the global namespace, which is considered poor form. This also doesn’t utilize Dojo’s packaging system. But it’s sufficient for the purpose of a few simple lines of code.

Now, let’s insert the dojoType in the markup and assign it to our widget:

Because we’ve required dojo.parser, and set parseOnLoad to true, the Dojo parser scans the document, finds the dojoType keyword, and converts that DOM element into a widget. The output is as expected:

Simple Widget

The same results happen if you create it programmatically. Note that if there were only programmatic widgets on the page, you wouldn’t need to require dojo.parser, nor set parseOnLoad in djConfig. A widget constructor takes two arguments; the first is a properties object, and the second is the DOM node that will be converted to the widget:

dojo.addOnLoad(function(){
	var obj = new Simple({}, dojo.byId("main"));
}

There’s an important change to Dijit from the 0.4.x release. Previously, you could specify any node, even document.body, and provide a third argument of “last” or “first”, and it would insert the widget in that node. This functionality is no longer supported, and instead the specified node gets replaced. If you wish to insert a widget in the body, say for a dialog window, you do as follows:

dojo.addOnLoad(function(){
	var obj = new Simple({});
	document.body.appendChild(obj.domNode);
}

In order, here are the methods that fire upon creation of a widget:

preamble()
Originating in dojo.declare, preamble is a new Dojo Core feature. It’s a pre-constructor accessory. By analogy, preamble is to constructor as postMixInProperties is to postCreate. Since preamble gets the same arguments as the constructor, you may extend another object, and jump in front of the constructor and change the arguments.
constructor()
Originating in dojo.declare, constructor has a new usage pattern. Previously, it fired last, which I didn’t find particularly useful nor accurate. It now fires early in the widget lifecycle, allowing early initialization with the arguments passed into the object. While more common in use, it’s not exactly necessary, as Dijit handles the job of converting your arguments into object properties.
postMixInProperties()
Originating in dijit._Widget, postMixInProperties is used more commonly by widget developers. That said, some of its duties are superseded by the addition of constructor and preamble. Its main purpose is firing after the properties have been set, but before the widget has been parsed and created. Pre-creation work on widget properties is typically done in this method.
postCreate()
Originating in dijit._Widget, postCreate is the “heavy lifter” of Dijit. This fires after creation, but before the widget is rendered to the page. At this time in the widget lifecycle, you have access to the widget’s nodes, so additional parsing, connections, styling, or even attaching more widgets is possible.
startup()
Originating in dijit._Widget, startup is somewhat misunderstood. startup doesn’t fire unless the widget is a child of another widget. And then it only fires after it, and all of its siblings have been created. Then they all fire together.

Knowing this, let’s create a widget to test its creation methods firing order.

dojo.declare(
	"Simple",
	[dijit._Widget], {
		preamble: function(){
			console.log("preamble - args:", arguments);
			arguments[0].name = arguments[0].prefix 
				+ arguments[0].suffix;
		},
		constructor: function(){
			console.log("constructor (", 
				this.name, ") - args:", arguments);
		},
		postMixInProperties: function(){
			console.log("postMixInProperties (", 
				this.name, ")");
		},
		postCreate: function(){
			console.log("postCreate");
			this.domNode.innerHTML = 
				this.name + " Simple Widget"
		},
		startup: function(){
			console.log("startup");
		},
	}
);
dojo.addOnLoad(function(){
	w = new Simple({prefix:"Foo", 
		suffix:"Bar"}, dojo.byId("main"));
})

Firebug Output

Note what’s happening here. Preamble occurs first, grabs the arguments object, edits it, and inserts a name key which the constructor acquires when grabbing the arguments. When constructor fires, this.name as a property has not been set, although it is set and available for the next two methods. Also, as stated earlier, startup was never fired.

Let’s do the same thing with the same widget in markup. In markup, you pass the parameters into the constructor as attributes in the DOM node.

Firebug Output

Whoa! What happened here? The properties didn’t get set. But after looking at all of the tests, this is how it’s done.

Time to put your Java hat on. The Dojo parser is only looking for class properties that you’ve preset. We need to “declare” them:

dojo.declare(
	"Simple",
	[dijit._Widget], {	
		prefix:"",
		suffix:"",
		preamble: function(){
			...other methods...

Firebug Output

Now we’re back on track. A word of caution on your “declared” variables. The Dojo parser is doing type-checking too. Currently, prefix:"" is being changed to the string “Foo” giving us the following output:

FooBar Simple Widget

Change it to “prefix:false”, and here are your results:

trueBar Simple Widget

Finally, let’s use some HTML in the widget. Keeping it simple, we’ll add this line:

templateString: "
${name}Widget
"

dojo.parser reads in this text. It catches instances of “${…}” and replaces it with the corresponding property. This is another change from Dojo 0.4.x. Notice the use of name in the template doesn’t include the keyword this!

To enable dojo.parser within a widget, we need to mixin the Dijit Template class, making the final code look like this:

dojo.declare(
	"Simple",
	[dijit._Widget, dijit._Templated], {	
		templateString: "
${name}Widget
" prefix: "", suffix:"", preamble: function(){ console.log("preamble - args:", arguments); arguments[0].name = arguments[0].prefix + arguments[0].suffix; }, constructor: function(){ console.log("constructor (", this.name, ") - args:", arguments); }, postMixInProperties: function(){ console.log("postMixInProperties (", this.name, ")"); }, postCreate: function(){ console.log("postCreate"); } } );

Firebug Output

With Dojo Toolkit 1.0, Dojo Core, and the new Dijit, widgets are now simpler and more powerful than ever. Demystifying them helps you get past the “how to do Dojo” and into “how to write cool widgets” mode.