Login Register

Creating a Widget Programmatically

In Part 2: Dijit, you saw how to instantiate (create an instance of) a dojo widget declaratively, using the "dojoType" attribute:

<div dojoType="dijit.TitlePane" title="Outer Pane">
   This is a title pane containing another title pane
   <div dojoType="dijit.TitlePane" title="Inner Pane">
      And this is the inner title pane...
   </div>
</div>

While this method is very convenient, widgets declared in this way are instantiated only when the page first loads. What if, however, you want to create a widget at some later time, e.g. as the result of a user-action? This is one case where we would want to instantiate a widget programmatically, which looks like:

var button1 = new dijit.form.Button(params, srcNodeRef);

Let's pick that programmatic example apart:

var button1
This is the name of the variable that will refer to the instantiated widget. You can use this variable to interact with the widget later (see Interacting With Widgets)
dijit.form.Button
This is the fully-qualified name of the widget you want to instantiate; freeing you to, perhaps, later instantiate yourmodule.form.Button (see Writing Your Own Widget Class)
params
An object whose properties map to the widget's properties. Dijit uses this object to initializes the widget's properties. Thus, if the "params" object in this case has a "label" property, dijit will set the dijit.form.Button's "label" attribute to the value of that property. See Setting Properties below for elaboration.
srcNodeRef
This is either a reference to an existing DOM node, or the id of an existing DOM node. When the widget is successfully instantiated, this node will be replaced with the widget's node. New in 1.0: You can skip this parameter for dijit.Tooltip, dijit.TooltipDialog and dijit.Dialog. Since they require no specific place on the page, there's no sense in providing one.

Thus, the programmatic equivalent of:

<div dojoType="dijit.TitlePane" title="Inner Pane">
  And this is the inner title pane...
</div>
from the example above would be:
var innerPane = new dijit.TitlePane( {title:"Inner Pane"}, dojo.byId("someDiv"));
When that line executes, the div with the id "someDiv" will be replaced with a TitlePane widget, with title "Inner Pane".


Setting Properties

Programmatically creating widgets allows extra freedom in the parameters. The following is perfectly legal:

var innerPane2 = 
    new dijit.TitlePane({
        title: 'Creating New '+docType,
        duration: 5 * 1000    /* 5 seconds, converted to ms */
    }, dojo.byId("someDiv"));

In declarative widgets, you may only pass strings. In programmatic ones, you can pass arrays, nested objects, Dates or Numbers as parameters. This isn't important for bundled Dijit components - they all work with strings - but it can make building your own widgets easier.

New in 1.0: When programmatically creating a widget class, style, and id now need to be specified as parameters to the constructor, not as attributes of the placeholder node. For example, the following is incorrect:

<script>
// Doesn't work in 1.0.  Class and style will be overwritten
new dijit.form.Button({},,dojo.byId("someDiv"));
</script>
<div id="someDiv" class="large" style="color:red"></div>

The correct code:

// Works in 1.0
new dijit.form.Button({ "class": "large", style: "color: red" }, dojo.byId("someDiv"));

startup()

Certain widgets require a startup() method to be called. When building widgets programmatically, you create the parent first, then add the children, and grandchildren... and finally call startup(). Startup() is called once on the top element in the hierarchy, after the whole hierarchy has been setup and the element inserted.

It's good practice to include the startup() call, even for widgets that have no children or do not require it.

accordion = new dijit.layout.AccordionContainer({}, dojo.byId("accordionShell"));
accordion.addChild(new dijit.layout.ContentPane());
accordion.addChild(new dijit.layout.ContentPane());
accordion.addChild(new dijit.layout.ContentPane());
accordion.startup();

Programmatic creation with IE6

A suggestion I got in the forums about this: IE is sensitive to adding stuff to the DOM while pages are loading.
It's better to put all the widget-adding code inside a dojo.addOnLoad() call, in order to have the browser finish
loading first.

Attaching to the Page - Dojo 0.9

In Dojo 0.9, the "sourceNodeRef" argument is a quick way to insert a widget into your page when instanciating programmitically. However, the drawback to this argument is that you must have a DOM node in mind, ready to be replaced as the "sourceNodeRef". What happens when you don't/can't have an expendable DOM node? Simple, create one on-the-fly and appendChild to your document. Next, supply this "placeHolder" node as the "sourceNodeRef" in your Dijit constructor.

Example:

function(){
    var placeHolder = document.createElement("div");
    dojo.byId("body").appendChild(placeHolder);
    var tt = new dijit.Tooltip({label:"This is a test!<br>This is a test!<br>This is a test!", connectId:"someNode"}, placeHolder);
}

Enjoy!

just to make a note, as of

just to make a note, as of 1.0 final (or trunk from a few checkins before tagging) this was fixed. In theory, you don't need to create a node (unless you need it somewhere specific in the dom before initialization) when creating a widget. if no srcNodeRef is found, one is created (killing all the errors in contentpane, and other layout widgets). ymmv. I usually put my domNodes where i want them, then turn them into widgets, but this is just a simple failover i guess.

A small fix

To make the example on this page clearer consider adding an id="someDiv" attribute to the inner pane so that it is clear this will be the target

for the dijit.