Core contains a lightweight extension that builds on top of
query
to provide a great way for
decoupling events and DOM manipulations from an HTML placeholder via
the behavior
module. It may not be
intuitively obvious at first, but the ability to define
behavior for nodes irrespective of the markup
itself can lend an immense of flexibility to a design. For example, it
allows you to concisely accomplish tasks such as assigning click
handlers to all anchor elements without knowing where or how many
anchor elements there will be. You use the same CSS selectors you
learned about in Table 5-1 to
find the nodes for attaching behavior to, so the possibilities are
almost endless.
The behavior
module currently
provides two API calls; the add
method allows you to queue up a collection of behaviors, and the
apply
method actually triggers
those behaviors:
dojo.behavior.add(/*Object*/ behaviorObject) dojo.behavior.apply( )
Basically, you use add
to
assign a new behavior to a collection of DOM nodes, but the behavior
isn't actually reflected until you call apply
. One of the reasons that it's a
two-step process is because the pattern of performing multiple
add
operations before a final
apply
occurs lends itself to a lot
of asynchronous communication patterns, described in Chapter 4.
Tip
Chapter 4 introduced a
data structure called Deferred
that is a staple in Dojo's IO subsystem. Deferred
s provide the façade of having a
thread available to operate on and lend themselves to successively
applying multiple callback and error handling functions. After
reading about Deferred
patterns,
the utility in providing separate functions for add
and apply
should be apparent.
The Object
that you pass into
add
and apply
is quite flexible and can accept a
number of variations. In short, the behavior Object
contains key/value pairs that map CSS
selectors to Object
s that supply
DOM event handlers. The DOM event handlers themselves come as
key/value pairs. Before the example, though, skim over Table 5-4, which provides a summary
of the possibilities.
Table 5-4. Behavior Object possibilities
Tip
Remember to provide the keys to the behavior Objects
as actual String
values whenever the CSS selector
requires it. For example, a behavior object of {div : function(evt) {/*...*/}
is fine
whereas {#foo :
"/dtdg/foo/topic"}
would not be valid because #foo
is not a valid identifier.
Take a moment to read through Example 5-1, which illustrates some of the possibilities as a working example.
Example 5-1. Example of dojo.behavior at work
<html> <head> <title>Fun with Behavior!</title> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" /> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js" djConfig="isDebug:true" ></script> <script type="text/javascript"> dojo.require("dojo.behavior"); dojo.addOnLoad(function( ) { /* Pass a behavior Object into dojo.behavior. This object is automatically added once the page loads*/ dojo.behavior.add({ /* The behavior Object is keyed by any combination of CSS selectors, which can map to a single behavior or a collection of behaviors */ /* Mapping a key to a function is equivalent to mapping to {found : function(node) { ... } } */ ".container" : function(node) { //apply some generic styling dojo.style(node, { border : "solid 1px", background : "#eee" }); }, /* Map the key to a collection of behaviors */ "#list > li" : { /* DOM events work just like dojo.connect, allowing you to act on the event */ onmouseover : function(evt) {dojo.style(evt.target, "background", "yellow");}, onmouseout : function(evt) {dojo.style(evt.target, "background", "");}, /* String values are published as topics */ onclick : "/dtdg/behavior/example/click", /* "found" is a general purpose handler that allows manipulation of the node*/ found : function(node) {dojo.style(node, "cursor", "pointer")} } }); /* Somewhere, out there...a subscription is set up... */ dojo.subscribe("/dtdg/behavior/example/click", function(evt) { console.log(evt.target.innerHTML, "was clicked"); }); }); </script> <head> <body> <div class="container" style="width:300px"> Grocery List: <ul id="list"> <li>Bananas</li> <li>Milk</li> <li>Eggs</li> <li>Orange Juice</li> <li>Frozen Pizzas</li> </ul> </div> </body> </html>
As the example demonstrates, any behavior you set up before the
page loads is set up automatically. After the page loads, however, you
need to first add
the behavior and
then apply
it. The following update
adds another click handler to list
elements:
dojo.behavior.add({ "#list > li" : { onclick : "/dtdg/behavior/example/another/click" } }); dojo.behavior.apply( ); dojo.subscribe("/dtdg/behavior/example/another/click", function(evt) { console.log("an additional event handler..."); });
Although one of the key observations you should be making is how
decoupled the actual behavior of the nodes are
from the markup itself, you hopefully just made the connection that
behavior
's apply
function provides you with a great
benefit: any behavior you supply on top of existing behavior is added
along with the existing behavior. In other words, new behavior doesn't
just blow away what was there before; you are able to add behavior in
layers and the book keeping is handled without any additional
intervention on your behalf.
Get Dojo: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.