Creating Dojo Widgets with Inline Templates June 24th, 2008 at 2:59 pm by Dustin Machi

I recently came across a situation where I needed to manage a set of nodes and widgets to perform a number of visual operations as well as manage some data between the client and a server back end. While this was a custom operation, it was common to a number of different places within the app. Initially, things were quite simple and I managed with a few functions and connections primarily using dojo.query(). In the end, I ended up with a simple way to make a dijit._Templated widget that uses its source node as a template instead.

Widgets can easily take advantage of existing source nodes to define how they might end up rendering. They might use the source nodes to define a data set. They could be widgets that manage a number of child widgets as is done with the various Dijit Layout widgets. However, under normal circumstances, a widget’s source node is replaced by the nodes generated from its template or the original source nodes are moved to a container node within your template. What we are looking for is a way to define a flyweight widget that can encapsulate behaviors and data, provides for dynamic template generation, and retains the utility of dojoAttachPoints and dojoAttachEvents from the templating system.

The good news is that it is very easy to do. Let’s look at a normal templated widget declaration:

dojo.declare("my.widget",[dijit._Widget,dijit._Templated],{
	templateString: '<div><div dojoAttachPoint="container"></div>
		<div dojoAttachEvent="onMouseOver:mouseOver">Go</div></div></div>"',
	postCreate: function(){
		// do something after I'm ready. Note: My children might not be 
		// ready yet, so dont' access them here!
	},
	startup: function(){
		// This fires after my children are available
	}
});

This is is a simple widget that does not do much. As you can see, it will end up creating a div containing two child divs at its declared location on the page. The first of these children has a dojoAttachtPoint attribute, which will create a reference to this DOM node at this.container in the widget instance. The second div has a dojoAttachEvent attribute which will connect that DOM node’s onMouseOver event to the widgets this.mouseOver() method.

There are numerous examples of using templates inside of Dijit and plenty of articles over at Dojo Campus or even here at the SitePen blog! But that’s not what we want as it is too static. Our templates will be defined as part of the Instance declaration instead of the widgets JavaScript declaration. To accomplish this goal, we simply need to declare the widget, and then override the buildRendering() and startup() methods provided by the dijit.Templated widget. We want to do something like this on our page:

<div dojoType="my.fly">
	<div dojoAttachPoint="container">Some Stuff</div>
	<button dojoType="dijit.form.button" dojoAttachEvent="onClick: go">
		Go!
	</button>
	<button dojoType="dijit.form.button" dojoAttachEvent="onClick: stop">
		Stop!
	</button>
</div>

So now we have a template:

<div dojoAttachPoint="container">Some Stuff</div>
<button dojoType="dijit.form.button" dojoAttachEvent="onClick: go">
	Go!
</button>
<button dojoType="dijit.form.button" dojoAttachEvent="onClick: stop">
	Stop!
</button>

The instance of my.fly will have a reference to the div at this.container, and the buttons, when clicked will call the fly’s go() or stop() methods respectively. As you can see there isn’t really any difference between this and a normal template provided by string or in a template HTML file. However, it’s easy for complex servers to generate a bunch of HTML and then wrap it with a fly widget to maintain it.

Let’s look inside my.fly to see how it ticks.

dojo.declare("my.fly", [dijit._Widget, dijit._Templated],{
	buildRendering: function(){
		// we already have the srcNodeRef, so lets just
                // keep it and use it as the domNode
		this.domNode = this.srcNodeRef;
 
		// call this._attachTemplateNodes to parse the template,
                // which is actually just the srcnode
		// this method is provided by the _Templated mixin
		this._attachTemplateNodes(this.domNode);
	},
 
	startup: function(){
		var node=this.domNode;
		this._supportingWidgets = [];
 
		// use a dojo.query to find all the child nodes that are widgets
		// and then get references to those widgets.  The widgets are
		// collected into this._supportingWidgets
 
		dojo.query("[widgetId]", node).forEach(function(n){
			if(n==node){return;}
			var id = dojo.attr(n,"widgetId");
			if (!id){return;}
			this._supportingWidgets.push(dijit.byId(id));
		}, this);
 
		// parse the widgets for dojoAttachPoints and dojoAttachEvents. 
		// Unlike the parse done in buildRendering, we're only going 
		// through the array of widgets in this._supportingWidgets;
 
		this._attachTemplateNodes(this._supportingWidgets, function(n,p){
			return n[p];
		});
	},
 
	go: function(){
		// do someting
	},
 
	stop: function(){
		//stop doing whatever it was go made me do.
	}
});

This flyweight mixin provides the above buildRendering() and startup() methods for easy reuse among a variety of flyweight widgets. Also included in this download are an example widget and test file, making it extremely easy to try this out with your application.

Tags: , , ,

3 Responses to “Creating Dojo Widgets with Inline Templates”

  1. CpILL says:

    Good article, but I’m still a little unclear about a few points.

    My flyweight I assume you mean the flyweight design pattern? If so I’m not sure I understand your interpretation of the pattern here. Do you mean that this warper flyweight widget does the mouse event capturing for the sub-widgets (as it seem in the example download)?

    What does the “[widgetId]” do/mean in the above dojo.query, I’ve never seen that before? I’m assuming from your code comments that it somehow “find all the child nodes that are widgets”?

    I like the design approach here and it was insightful as to the inner workings of the dijit._Template widget system in Dojo.

  2. Dustin Machi says:

    By Flyweight I didn’t mean anything quite as specific as that design pattern. I guess my usage is somewhat in correct, though I’ve heard others refer to adding behaviors like this to the existing dom as a flyweight widget. I could probabably argue and rationalize the similarities between what this does and the actual design pattern, but doesn’t seem like it will get anyone anywhere, so I won’t. :)

    The “[widgetId]” query looks for domNodes that have the “widgetid” attribute on them (which all instantiated widgets do/will have).

  3. Leelakrishna says:

    Hello,

    I am new to Dojo and trying to develop an front end design for my project and i am using accordian menu for my application.I saw the site “http://www.dojocampus.org/explorer” and i need to get that left side menus like{”data”,drag n drop,etc..} like my menus are {”payslips-sublinks are ‘Jun-08′,’jul-08′”,”TaxDeclaration-sublink is:’taxdeclarationsheet’”,etc..}
    I am not getting that left side menu exactly like labels…
    Can any body help..

    Thanks In Advance,
    Leelakrishnad.

Leave a Reply