Decoupling Widget to Widget Interaction with Dojo
As a programmer, you should try to think of how you can write your code in a way that is maintainable and loosely coupled from other parts of your application. Loosely coupled basically means that you don’t tie down functionality and modules to be dependent on other parts of your application. In a way, you want to try and categorize the functionality and keep the functionality in one spot. Take our modern day telephone system for example. If you wanted to use your phone at home to call your friend on their phone on the other side of the world, the phones themselves don’t have to know each other. All they are concerned about is how to interact directly with the telephone system. The telephone system simply requires a telephone to know how to dial out and to be able to receive a phone call when the line is being rung.
Even though the two phones are separate entities in their own right, they are small pieces of functionality in the scope of the whole phone system that reaches the ends of the Earth. On a much smaller scale you want to do that with your application—break it up into smaller chunks of functionality.
This very concept can be applied to modules that you have on your webpages. Modules or more specifically Widgets, can and should be single independent pieces of functionality on a given page. However, lets say you want one module to interact with another, without breaking the cardinal rule of coupling them together? The answer is to use Dojo’s very powerful yet extremely easy-to-use topic system (aka publish/subscribe).
The dojo.publish() method allows you to build in a simple way for your widget to broadcast a message, which can contain objects of data, that anybody who is listening for that message will receive. The dojo.subscribe() message allows you to setup listeners for that message. It works very much like event listeners when you listen for DOM events such as clicks of a button. Only, instead of the DOM announcing an event, you are announcing your own custom event that something occurred.
How does this all work exactly? Well, let’s first take a look at a demo. It’s pretty simple to play with, just type a message in the textbox and click “Send Message”. You’ll notice your message show up on the right with a timestamp. You can also add more message displays by clicking the button “Add Message Display”. You can add as many of these as you want and every one of them will receive the message that you type. Furthermore, any message display box that you have checked the box “Allow Images”, you will be able to click the “Send Image” button and an image will show up in the appropriate display boxes.
This is a lot easier than it appears. Let’s break down what the magic is. You can think of the interaction between publish and subscribe kind of like watching TV. If you want to watch a TV show, you tune into, say, Channel 7 and you will see the broadcast. dojo.subscribe() works kind of the same way. You give it a topic to listen to as a String, then provide it a function that you want to execute when it receives data on that channel:
dojo.subscribe("com.hayes.demo.topics.SendMessage", this, this.onSendMessage);
Like I said, the first argument which is the topic you want to listen to is a string. It can be any string you want. The examples in the Dojo docs use a folder path notation (e.g. com/hayes/demo/topics/SendMessage), but I prefer the dot-notation since it is widely recognized. The second argument that I provide is the scope of which the callback function should be run in, and the third argument is the reference to the function (which could also have been provided as a string “onSendMessage”).
To broadcast a message on that same channel you simply use dojo.publish():
dojo.publish("com.hayes.demo.topics.SendMessage", [{ message: this.msgNode.get("value") }]);
Here I use the same string that I used in dojo.subscribe, and my second argument is the data I want to send along. Note that here whatever data you send, has to be inside the first element of an array (of course its easiest to simply wrap your data in a set of square brackets). In the case above, I’m sending a simple plain object with a property labeled as “message” with a value of the text that was inputted in the textbox. Any other module on the page you want to receive this same data, you simply use dojo.subscribe() as above and every time a message is sent, all those functions will receive it. That’s why when you click “Add Message Display” they all receive the same message that the Control Panel sends. Every time those modules they get created, they are subscribed to the “com.hayes.demo.topics.SendMessage” topic.
This very same methodology is applied with the checkboxes in incrementing the count on the control panel, as well as sending the images. The difference here is that by default, these modules are not subscribed to the “com.hayes.demo.topics.SendImage” topic so if you try to send an image, it doesn’t get sent. However, once you tick the checkbox to allow images, the module will begin to receive the images (which in this case is simply a url for the MessageDisplay box to show in an img tag) that are sent.




