Showing posts with label dojo.behavior. Show all posts
Showing posts with label dojo.behavior. Show all posts

Sunday, September 19, 2010

dojo.behavior and jquery live

My last blog post mentioned that dojo.behavior was modeled after Ben Nolan's plugin which in turn has since been replaced by jquery.live. After reading this, I made the assumption that jquery's live and dojo.behavior were analagous. Even after coding up a quick example using dojo.behavior to mirror the jquery live() example, I came to the conclusion that these two API methods offered pretty much the same functionality.

However, after a quick discussion on the #dojo IRC channel, Brian Arnold pointed out a subtle but important difference between the two APIs. Apparently, jquery's live method listens for bubbled events on the document element and then maps these events back to jquery.live declarations. dojo.behaviour is a little different. It listens for events fired from the selector on which the behavior is added in the first place. So, if I changed my previous example to look like this:
dojo.behavior.add({
'p': {
onclick: function(evt) {
dojo.place("<p>Another paragraph!</p>", dojo.query('body')[0]);
}
}
});
dojo.behavior.apply();

New paragraphs would only be added when the user clicked on the first 'Click Me' paragraph. However, with jquery, if I altered the original example to look like this:
$("p").live("click", function(){
$("body").after("<p>Another paragraph!</p>");
});

Even clicking on the 'Another paragraph' would result in new p dom nodes being added to the document.

Cheers for pointing out this difference Brian. Also - see the comments below for one other point by Brian.

One other difference between the two APIs was pointed out by Pete Higgins - dojo.behavior includes a 'found' function which operates a little like this:
var myBehavior = {
// all <span> nodes
"span" : {
// for each:
found: function(n){
console.log('this is the first time I have encountered ', n);
}
}
};
dojo.behavior.add(myBehavior);

Tuesday, September 14, 2010

dojo.connect vs. dojo.behavior

Having used dojo for the past few years, I've become very familiar with using dojo.connect to list for events being fired on objects. The API is simple, clear and concise:
var h = dojo.connect(dojo.byId("myNode"), "onclick", myInstance, "reactToNodeClick");

Plenty of documentation already exists on dojo.connect, so I'm not going to rehash it out here. Reading a recent article on dojo.behavior and couldn't help but agree that there are an enormous amount of similarities between dojo.connect and dojo.behavior. Apparently, dojo.behavior uses the dojo.connect plumbing under the covers, so I was curious to figure out why there was a separate dojo API entry-point to this exact same functionality. dojo.behavior must be offering something above and beyond dojo.connect, or at least it must expose new functionality for connecting to dom and custom events. According to comments on this article, dojo.behavior is based on Ben Nolan's plugin which seems to have been deprecated in favor of jquery's live method. Taking a look at the docs for jquery, I took a shot at converting their example to use dojo.behavior:
<!DOCTYPE html>
<html>
<head>
<style>
p {
background: yellow;
font-weight: bold;
cursor: pointer;
padding: 5px;
}
p.over {
background: #ccc;
}
span {
color: red;
}
</style>
<script type="text/javascript" src="dojotoolkit/dojo/dojo.js">
</script>
<script type="text/javascript">
dojo.require("dojo.behavior");
</script>
</head>
<body>
<p>
Click me!
</p>
<span></span>
<script>
dojo.addOnLoad(function() {
dojo.behavior.add({
'p': {
onclick: function(evt) {
dojo.place("<p>Another paragraph!</p>", dojo.query("p")[0]);
}
}
});
dojo.behavior.apply();
});
</script>
</body>
</html>

So, it seems that dojo.bevahior's main advantages over dojo.connect are:
1. behaviors are added to dom elements which have yet to be inserted into the overall document. This allows the developer to organize all the behavior for a page in one place and also allows for quickly adding behavior to dynamically added dom elements. This stackoverflow question has a pretty nice explanation of this.
2. You can add multiple behaviors to elements all in the one statement. Example:
dojo.behavior.add({
'.foo' : {
found: function(node) {
// do something with each node found
}
}, 
// shortcut for found
'.foo2' : function(node) {
// do something with the node
}
});

although, it could be argued that a combination of dojo.forEach and dojo.query would allow a developer to declare multiple dojo.connects in one statement. For example:
dojo.forEach([".foo", ".foo2"], function(item) {
dojo.query(item).connect("onclick", function(node) {
// do something with the node.
});
});

Unless I'm missing something in the dojo.behavior API I don't see a way to disconnect all the previously added behaviors. I use dojo.disconnect quite a bit when using dojo.connect to clean up after myself (phiggins article again). dojo.behavior.add doesn't return an array of handles so you cannot remove behavior once it has been added. A global suspend/resume API might be a useful addition to the dojo.behavior API to allow a developer to stop/start behaviors. It could even look like this:
dojo.behavior.suspend(selector);
dojo.behavior.suspendAll();
dojo.behavior.resume(selector)
dojo.behavior.resumeAll();

// possible usage
dojo.behavior.add({
'p': {
onclick: function(evt) {
dojo.place("<p>Another paragraph!</p>", dojo.query("p")[0]);
}
}
});
dojo.behavior.apply();
// stop all behavior on p elements that were just applied in the previous statement.
dojo.behavior.suspend('p');
// allow behaviors on p elements again
dojo.behavior.resume('p');

I dunno … that seems hackish when compared with dojo.connect/dojo.disconnect.

Even after this exportation into dojo.behavior, I'm not sure I'd ever use it over dojo.connect/disconnect. dojo.connect/dojo.disconnect gives me a level of granularity that I'm comfortable with. Even searching through the dojo source code for references to dojo.behavior, I don't really see it being used at all in internal framework code (dojo.connect/dojo.disconnect is used EVERYWHERE though).

Can you see any other uses for dojo.behavior - why would you chose to use it over dojo.connect/dojo.disconnect?

Some other useful links:
http://paulirish.com/2010/on-jquery-live/
http://forum.jquery.com/topic/jquery-live-jquery-fn-live-discussion