Dojo 0.9 is a different beast than any Dojo before it. It’s smaller, it’s (much) faster, and it “feels” different in many ways. As Jon Sykes noted, “everything is familiar yet strangely different”. I could go on for hours about why
dojo.query() is completely indispensable or how having
dojo.behavior as a part of Core changes everything, but there’s some fun stuff up the stack too. In particular, new parser bears mention, and a bit of explanation. In addition to now letting you build instances of any class (not just widgets), it also lets you configure their behavior as well as their properties.
For a long time systems like Flex and Laszlo have had a corner on naturally mixing behavior with markup. HTML’s native <script> tag doesn’t provide any context, and worse, can’t provide a way to be triggered by a particular event or action (outside of proprietary extensions). Several use-cases are important:
- Scoped execution
- Event-driven execution
- Attachment vs. replacement
In Dojo 0.9 we took a hard look at them and devised
<script type="dojo/method"> and
<script type="dojo/connect">. Lets take a quick tour and show how it makes writing event handlers natural, building new widgets a snap, and over-riding built-in behavior trivial.
Scoped, Event-Driven Execution
In regular-old HTML script tags, the keyword
this has no relationship whatsoever with the location of the
<script> tag to it’s parent elements in the document. This makes some tortured sense, but when we’re building large component hierarchies, trying to find elements by id (or CSS selector) and then tying some customized behavior to them can seem like more trouble than it’s worth. In Dojo 0.4.x, you might have done something like this:
Which worked fine for one or two expressions in reaction to an event, but what about when you wanted to do something more complicated? The inline style kinda falls apart and you were forced to wire things up more manually (still using 0.4.x APIs):...
Do this multiple times and you’ll quickly start looking for the manual to figure out how to build widgets programmatically so that you don’t have to try to match up when your script executes with when the widgets are available. Also, by moving to that manual style of wiring, the
thiskeyword now points to the “wrong” place. In the inline example
thismapped to the widget, but without extra work,
thisin the second example points to the global object. Not really what we want. In 0.9 we can write it much more naturally:...
type="dojo/connect"lets us delay execution of the script block because the browser will skip it when it executes scripts of types it understands (like
onDownloadStart. We can also note that
thisnow points to the widget instance directly. No more boilerplate to manage ids or look up widget instances. The nesting of the
<script>block inside of the widgets definition on the page is enough to set up the relationship.
eventproperty is also interesting. Instead of having to manually call
dojo.connect()to wire a function to a behavior, we can specify on the
<script>itself what the function we’re defining should do. In fact, thinking of these kinds of
<script>blocks as defining functions is perhaps the best way to visualize what they do and how they work.
If all we want to do is log out the
hrefproperty, Dojo 0.9 still lets us do that with the inline style we saw first:...
Looking at that harder, though, it’s not clear just by looking at it whether or not specifying a handler as an attribute replaces (as with regular value attributes) or connects to an existing behavior. Using the new
<script>types, we can also clarify that too.
Connect Or Replace?
The difference between
<script type="dojo/connect">, simply stated, is that
dojo/methodreplaces the specified event handler whereas
dojo/connectis added as a listener to the original behavior. Simple.
We can then take our earlier example and change what this particular widget returns from its
onDownloadStartmethod by specifying our handler as a method:...
Seems straightforward. But what about if we don’t specify an
event? Glad you asked. Luckily, the new system treats this as though you are executing code just after the instance is created, analogous to
dojo.connect(this, "constructor", ...), assuming that were even valid (which it’s not). This means we can use these new
<script>types as de-facto instance configuration blocks.
Lastly, to head off the “but what about performance?” questions at the pass, the new Dojo parser is much much faster than the 0.4.x system and as a result adding methods and connections this way often falls into the noise. There is some overhead to locate and create function objects out of the script bodies, but it’s far outweighed by the usability advantages and general 0.9 improvements in parser performance.