Login Register

More on The Javascript Object

Now we'll see how you write the javascript portion of a widget.

Previously we looked at the CSS and the HTML used to define a widget. The third and final component to widgets is a javascript class to handle widget rendering details and events on the widget.

defineWidget

The first step to writing the javascript for a widget is to call defineWidget. Below I'm defining a widget called my.widget.html.Foo that extends dojo.widget.HtmlWidget,the base class for most widgets. (We'll talk about different base classes and what "html" means in a later document.)

dojo.widget.defineWidget("my.widget.Foo", dojo.widget.HtmlWidget, {

function() {

// do initialization tasks, make instance properties

},

{

...prototypical properties (in object notation)...

}

);

Using dojo.widget.defineWidget, the tasks below are performed automatically:

  • register widget package (tell dojo the namespace contains widgets)
  • add the parse tree handler (identify a markup tag with the widget)
  • set the widgetType
  • invoke ancestor constructor
  • inherit from ancestor prototype

Alternately, I might want to extend an existing widget. Here I'm making an enhanced version of Foo called FooPlus:

dojo.widget.defineWidget("my.widget.FooPlus", my.widget.Foo, { 

function() {

// do initialization tasks, make instance properties

},

{

...prototypical properties (in object notation)...

}

);

Parameters

OK, that's the skeleton for the widget, but what do we put inside? The first thing to think about are the parameters that are used when you construct the widget. Every widget can take parameters. For example:

Where are the parameters defined, and how do you set their types? Actually, they are just properties in the javascript class. In this case:

    toggle: "",			// string

toggleDuration: 0, // integer

onClick: function(){} // function

Javascript doesn't have types, so how do we specify the types of the parameters? By specifying an example. In the above case, 0 means integer and "" means string.

Note: don't set them to null or it won't work!

Default values:

You can also specify default values in the javascript file. If the user doesn't specify a value for a parameter the default is used. For example:

    toggle: "fade"

Important Properties To Set

Next, you need to set certain properties that define how the widget operates.

isContainer

True/False. Must be set to true if the widget has child HTML or child widgets

snarfChildDomOutput

True/False. Set this to true if you are making something like a container node, where the input is just a list of widgets. It resolves issues where a child's generated DOM tree cannot be put back into the same place the source dom tree was. (Because [td] cannot be a child of [div], etc.)

templatePath

The path to the template HTML file, if one exists for the widget. This needs to be a dojo URI object, and is normally one of the two options shown below:

dojo.uri.dojoUri("src/widget/templates/HtmlFloatingPane.html"),

or

dojo.uri.moduleUri("mywidgetset","widgets/html/MyWidget.html"),

templateCssPath

The path to the template CSS file, if one exists for the widget. This needs to be a dojo URI object, and is normally one of the two options shown below:

dojo.uri.dojoUri("src/widget/templates/HtmlFloatingPane.css"),

or

dojo.uri.moduleUri("mywidgetset","widgets/css/MyWidget.css"),

templateString / templateCssString

If the CSS or HTML for a widget is very simple, you can specify it in the javascript rather than using templatePath/templateCssPath to refer to other files. This is what the dojo build process does automatically to embed templates/CSS in your widget code when you specify the intern-strings option.

templateString: "
Simple Template
",

templateCssString: ".simple { color:blue; font-size:12pt; }",

Initialization Methods

Inside a widget file you will notice a number of functions for initialization. The most important ones are described below in the order they are called during the widget creation process.

postMIxInProperties()

this is called after the properties (see previous section) are initialized to the user specified values, but before the HTML template is instantiated.

Typical actions to perform here are validating and adjusting parameters provided to the widget.

fillInTemplate()

This is called after the template has been instantiated, so this.domNode points to the generated DOM tree. However, the children DOM nodes (for containerNode) and widgets haven't yet been copied over, and the widget's DOM node has not yet been placed in the actual HTML document.

Typical actions to perform here include:

  • Enabling or disabling parts of the widget
  • Applying styles/classes/etc
  • Creating widgets that attach to nodes in the template
  • Setting initial state

postCreate()

This is called after the children dom nodes and widgets have been instantiated. However, for programatically created widgets, none of the children exist yet, because they are added after createWidget() finishes, via the addChild() call.

Typical actions to perform here include:

  • Connecting event handlers

  • Manipulating parent or child nodes (with the above caveat)

Arrays, Objects, and Statics

Widget attributes that are Arrays or Objects need to be declared in the initializer() function, rather than like other variables (numbers or strings), so that they are not inadvertently shared between other instances of the same widget.

On the other hand - to make a static variable (i.e. a variable that is shared across all instances of the widget), just take advantage of the above issue:

    // static1 and static2 are shared across every Foo widget

statics: { static1: 0, static2: "" }
    this.statics.static1++;    // increments the single copy

Important Variables

this.domNode - points to root of generated tree

this.containerNode - place where child HTML was attached

this.children - array of child widgets