Of Dijits and DOM nodes

June 5, 2010 by Ken · 2 Comments 

This shall be the first of an unpredictable number of posts wherein I discuss recurring sources of confusion for newcomers to the Dojo Toolkit.  I’ll be tagging such posts dojofaq, for future reference.

One of the main attractions to the Dojo Toolkit is Dijit, a library of skinnable widgets built upon the functionality available in dojo core (Dijit = Dojo + widget).  However, diving head-first into Dijit without a primer can quickly lead to various common points of confusion, which I’ve seen come up repeatedly in the IRC channel.  This article aims to cover a bit of the basics, demystifying and addressing questions such as the following:

  • “Why doesn’t dojo.byId('mywidgetid').attr('value') or dojo.attr('mywidgetid', 'value') do what I expect?”
  • “I dojo.destroyed my widget, but when I recreate it it tells me the id is already registered!”
  • “I’m connecting to my widget’s onclick but it’s not firing!”

These questions all have a common source – the confusion between working with Dijit widgets, versus working simply with DOM nodes.

DOM Nodes

Anyone who’s been tinkering around with HTML and JavaScript for any significant amount of time should already have some clue as to what a DOM node is:  a node in a DOM tree, which itself is a representation of a document composed in a markup language such as HTML.  The Document Object Model provides means of accessing and manipulating the nodes in the document tree. All major browsers have supported the DOM standards to varying extents for years, and many of the functions in Dojo base serve the purpose of simplifying, normalizing, and/or expediting DOM tasks.

Let me underline that last point a bit differently:  when you’re working with dojo base methods, like dojo.byId, dojo.attr, dojo.destroy, etc., you are operating directly on DOM nodes.

Widgets

What’s in a Widget?

Let’s clear this up right now:  a widget is not a DOM node; it is far more.

A widget is comprised of one or more DOM nodes with associated JavaScript logic; together these form an atomic unit with some intended range of functionality.  Add relevant CSS styling provisions, and you now have a fully-skinnable UI component.

Let’s say you’ve declared an instance of a widget, and have given it the id “foo”.  Coming fresh out of Dojo base camp, and perhaps especially if you’re approaching Dijit using declarative HTML to instantiate widgets, you might be inclined to try grabbing that widget using dojo.byId('foo') – but think about what you’re asking for here.  You’re asking dojo to fetch you the DOM node with the id “foo” – the DOM node, not the widget!  A DOM node, whether part of a widget or not, is still pretty much just a DOM node; this one just happens to have a higher calling.  But how do we get a handle on that higher calling?

As it turns out, Dijit maintains its own registry; as widgets are instantiated, they are also centrally “registered” so that the Dijit manager can keep track of them, at the same time providing methods like dijit.byId and dijit.byNode for later accessing them.  Thus, by calling dijit.byId('yourwidgetid'), you get back the entire widget object, complete with whatever functionality is encapsulated within.

Destroying Widgets

Just as there is a unique means of accessing widgets, there is also an appropriate way to destroy them.  You may have guessed by now that dojo.destroy('someid') will only destroy the DOM node with the given id.  While this may destroy some or all visible traces of the widget in the DOM, it does nothing with any Dijit information.  So how do we fully destroy a widget?

All widgets (as in, all instances of dijit._Widget and subclasses thereof) have three destruction-related methods:

  • destroy: handles destruction of the widget itself, as well as any supporting widgets (i.e. those defined in a widget’s template).
  • destroyDescendents: destroys any child widgets within this widget, including any grandchildren, etc.  (calls destroyRecursive on all child widgets).
  • destroyRecursive: calls both destroyDescendants and destroy (in that order).  This is usually the real method of interest.

Widget Events

Another frequent point of confusion is often encountered when first playing with connecting to events on widgets.  Just as widgets are not DOM nodes, widget events are not technically DOM events.  They are, however, often mapped directly to DOM events on a DOM node within the widget.  To differentiate between DOM and widget events, the latter regularly follow camel-case nomenclature, so the onclick DOM event would be connected to an onClick widget callback, for instance.

The base class dijit._Widget includes logic which will automatically hook up callbacks for many common events to its topmost DOM node when those events are first used.  The API documentation page for dijit._Widget enumerates these callbacks, among the other methods of the class.

Conclusion

Armed with what we’ve learned, let’s recap those questions from the beginning of this article:

  • “Why doesn’t dojo.byId('mywidgetid').attr('value') or dojo.attr('mywidgetid', 'value') do what I expect?”

Functions in the dojo namespace aren’t generally expected to be aware of dijit stuff.  You should be using dijit.byId('mywidgetid').attr('value') for the above purpose (or get and set instead of attr in Dojo 1.5).

  • “I dojo.destroyed my widget, but when I recreate it it tells me the id is already registered!”

This is another instance, like the previous, of mistakenly using a function from the dojo namespace.  mywidget.destroyRecursive() is most likely what you’re really interested in here.

  • “I’m connecting to my widget’s onclick but it’s not firing!”

Widgets don’t tend to have onclick callbacks; what they do tend to have is an onClick callback (note the capital C), which usually maps to the onclick DOM event of the top DOM node of the widget.  Try connecting to onClick instead, or look into the documentation of the widget in question to see what callbacks it exposes.

I hope this article has helped dispel a few (dis)illusions.  If you’ve got questions, suggestions for future articles, or think something in this article could be clearer, feel free to comment.

Further Reading

Wikipedia’s article on DOM
W3C’s page on DOM
Mozilla’s DOM reference for the Gecko engine

API documentation for dijit
Documentation index for dijit
API documentation for dijit._Widget
Documentation page for dijit._Widget

Comments

2 Responses to “Of Dijits and DOM nodes”
  1. Javier says:

    Hey, Great articles. Well written, clear and above all very informative in things not explained somewhere else.
    I’ve been using dojo for a while, wish someone had been this before.
    Now, do you know something about functional testing against widgets?

    • Ken says:

      Thanks for the comment.

      Unfortunately I haven’t really delved into functional testing UIs, beyond giving Selenium a try for a few days at one point before getting grabbed into another project. Selenium seems capable, though I do expect that had I continued, I would have faced some challenges with it, but YMMV depending on your application.

      I am under the impression that Dojo’s own DOH framework is far more suited for testing individual components than for functional-testing a real application, but I haven’t really gotten into it yet to find out.

Speak Up