Preface to DnD: topics

This is a quick cookie to cover a really cool topic. Custom events and Dom Events are all well and good for method-to-method functionality. It is a really common use case to connect some event happening to call another function, but when you get into really ambiguous, large applications, you need some mechanism to just say “hey, something has happened, act accordingly” … dojo.publish and dojo.subscribe provide just that mechanism.

As the title states, this is a primer cookie to a DnD cookie (which uses topics to communicate between drag-able objects), so read up if you are unfamiliar, or just need something to refresh with over coffee.

So we all understand the concept of connecting to a dom event, a really common one being “onclick”:

var node = dojo.byId("someNode");
dojo.connect(node,"onclick",function(e){
  /* node id="someNode" clicked */
});

… run some anonymous function when some node is clicked. pretty straightforward.

What if that button/node/whatever was meant to call some action “globally”: send out some alert, or otherwise have some way of communicating ambiguously with any number of “listening” elements. Publish it, and tell folks to subscribe to the topic.

lets convert our “onclick” listener to a publish message, so other’s can know about it:

var n = dojo.byId("someNode");
dojo.connect(n,"onclick",function(e){
     dojo.publish("/node/clicked",{
     // some message to send out:
         message:{
             text:"This node was clicked",
             node:e.target // our event target
         }
     });
});

At which point, nothing actually happens. That’s okay, because the ambiguity we’re looking or has already occurred. We’re already sending out whatever message we intended to send. Now, any element which wants this information needs to subscribe to it:

dojo.subscribe("/node/clicked",function(topicData){
    // when we get this topic, do "something" about it:
    console.log('someone, somewhere, clicked:',topicData.node);
});

This can happen as often as we want, in as many scopes as we want. Each subscription should handle it’s own logic. If a particular subscription doesn’t want to know about something going on, all it has to do is unsubscribe. A dojo.subscribe() call returns a handle, made just for this.

var handle = dojo.subscribe("/node/clicked",function(message){
     // example of connect-once to a subscription
     console.log("i got a click",message);
     dojo.unsubscribe(handle);
});

This shows how to connect to a topic once, and stop listening. A more common use would be to have some topic being published, and when some other topic publishes, go ahead a stop listening:

// setup some connections:
var n = dojo.byId("someNode");
dojo.connect(n,"onclick",function(e){
     dojo.pushlish("/got/clicked",{ node:e.target });
});
var n2 = dojo.byId("cancelNode");
dojo.connect(n2,"onclick",function(e){
     dojo.puslish("/stop/listening",{ uselessHere:"now!" });
});
// here's the topic stuff:
var handle = dojo.subscribe("/got/clicked",function(data){
     alert("alert()'s are annoying.");
});
dojo.subscribe("/stop/listening",function(data){
     // anytime the /stop/listening topic is published, reallly stop listening:
     if(handle){ dojo.unsubscribe(handle); } // thank jebus: stop the alert()
});