odoe

Stay on topic

Blog Post created by odoe on Dec 2, 2014

Previously I had talked about how you can extend dojo/on to do some neat event listener tricks. This time, I'd like to talk about dojo/topic. You can think of the topic module as an EventBus. Here is a good (non-JavaScript) explanation of an EventBus when it comes to Java. It’s basically a singleton or global messaging system for your application.

 

What you may be doing now

Let's say for example you had two widgets that you wanted to use in your application and you wanted to pass information between the two of them. You could try and pass each widget into each other and try listening for events, but that would get sloppy pretty quickly. You could just have a single module listen for events in each widget similar to something like this.

 

on(widget1, 'load', function() {
  widget2.doSomething();
});
on(widget2, 'load', function() {
  widget1.doSomething();
});

 

That's not so bad, but if your application has to grow, you're going to find this can get plain ugly and difficult to debug after a while.

 

What you could be doing

This is where dojo/topic comes in. Each widget can use dojo/topic to subscribe to certain messages. This is similar to events, but is not dependent on individual dijits.

 

topic.subscribe('dijit-message', function(payload) { /** do something **/ });

Then any dijit or other part of you application can publish to that channel.

 

topic.publish('dijit-message', { message: 'hello' });

 

Notice the subscibe/publish methods? That's right, dojo/topic is a pubsub. BOOM!

 

Demo

Here is a really simple demo of how you might use this in your application.

require([
  'esri/map',
  'dojo/_base/declare',
  'dojo/on',
  'dojo/topic',
  'put-selector',
  'dijit/_WidgetBase',
  'dojo/domReady!'
], function(Map, declare, on, topic, put, _WidgetBase) {
  
  var Dijit1 = declare([_WidgetBase], {
    postCreate: function() {
      this.btnNode = put(this.domNode, 'button', 'Click me!');
      this.own(on(this.btnNode, 'click', this.onClick.bind(this)),
        topic.subscribe('dijit2-click', function(data) {
        var oldValue = this.btnNode.innerHTML;
        this.btnNode.innerHTML = data.value;
        setTimeout(function() {
          this.btnNode.innerHTML = oldValue;
        }.bind(this), 1000);
      }.bind(this)));
    },
    onClick: function() {
      topic.publish('dijit1-click', { value: 'Hello from dijit1!' });
    }
  });
  
  var Dijit2 = declare([_WidgetBase], {
    postCreate: function() {
      this.btnNode = put(this.domNode, 'button', 'Click me!');
      this.own(on(this.btnNode, 'click', this.onClick.bind(this)),
        topic.subscribe('dijit1-click', function(data) {
        var oldValue = this.btnNode.innerHTML;
        this.btnNode.innerHTML = data.value;
        setTimeout(function() {
          this.btnNode.innerHTML = oldValue;
        }.bind(this), 1000);
      }.bind(this)));
    },
    onClick: function() {
      topic.publish('dijit2-click', { value: 'Hello from dijit2!' });
    }
  });
  
  var d1 = new Dijit1(null, document.getElementById('dijit1'));
  var d2 = new Dijit2(null, document.getElementById('dijit2'));
  
  var map = new Map('map', {
    center: [-118, 34.5],
    zoom: 8,
    basemap: 'topo'
  });
});

 

Can you see the light?

Hopefully, you can see how this might be a powerful way of passing data between your custom widgets in your application. I use this quite a bit for managing what widgets are visible in an application. Say, click a button, show widget1, click another button, close widget1 and open widget2. I also use it to pass around a feature that maybe other widgets depend on.

 

There are a lot of creative ways you could use dojo/topic in your application. This was just a quick intro to a module that I find useful on a daily basis.

Outcomes