HTML5, CSS3, jQuery, JSON, Responsive Design...

Backbone.js and jQuery pub/sub

Michael Brown   June 5 2012 01:45:20 AM
Backbone.js is fast becoming my JavaScript framework of choice, but marvellous as it is, the tight coupling of models and views can seem a little restricting.  What if you have other observers, outside of your tight model/view couplings, which you also need to notify when things change?  Well, jQuery now has this neat little feature called jQuery.Callbacks() ....


jQuery Pub/Sub

Before I started using backbone.js, I was implementing the Publish/Subscribe pattern (a.ka. "pub/sub" or the Observer pattern) by way of the new jQuery.Callbacks() functionality that was added in jQuery 1.7.  The documentation page for jQuery.Callbacks() has an example of exactly how you can use it for pub/sub.  It all revolves around function that they've called jQuery.Topic(), the code for which I've reproduced in the box below.  Note also the global variable topics, which jQuery.Topic() requires:

var topics = {};

jQuery.Topic = function( id ) {
var callbacks,
   method,
   topic = id && topics[ id ];
if ( !topic ) {
   callbacks = jQuery.Callbacks();
   topic = {
       publish: callbacks.fire,
       subscribe: callbacks.add,
       unsubscribe: callbacks.remove
   };
   if ( id ) {
       topics[ id ] = topic;
   }
}
return topic;
};


jQuery.Topic() is basically a front-end for using jQuery.Callbacks().

The observer(or subscriber) objects take out "subscriptions" to various events (or "topics") by calling the jQuery.Topic's subscribe function.  The observer supplies to jQuery.Topic two parameters: the name of the event/topic in which it is interested (supplied as the parameter passed to jQuery.Topic itself) and the callback function that is to be triggered when that event happens (supplied as the parameter to the jQuery.Topic's subscribe function).  jQuery.Topic stores these subscriptions and callbacks in the topics global object.

A "publisher" object can then trigger one of these events via jQuery.Topic's publish() function.  Again, this passes the event/topic name as the parameter to jQuery.Topic itself.  Additional parameters can be included in the publish function and these will be be passed to the callback functions that were defined in any subscribers to that topic.

Here's some examples, of publishing and subscribing, again copied from the jQuery documentation page.

// Here's the Subscribers. "mailArrived" and "mailSent" are two topics.  fn1, fn2 and fn3
// are callback functions that will be triggered when the topics are "published".  They'll
// just do a quick console.log of any parameter that they're passed.
$.Topic( "mailArrived" ).subscribe( fn1 );
$.Topic( "mailArrived" ).subscribe( fn2 );
$.Topic( "mailSent" ).subscribe( fn1 );

// Here are the Publishers.  Same two topics again and note the extra parameters
// "hello world" and "woo! mail", which will be passed to the Subscribers' callback functions.
$.Topic( "mailArrived" ).publish( "hello world!" );
$.Topic( "mailSent" ).publish( "woo! mail!" );

// Here, "hello world!" gets pushed to fn1 and fn2
// when the "mailArrived" notification is published
// with "woo! mail!" also being pushed to fn1 when
// the "mailSent" notification is published.

/*
output:
hello world!
fn2 says: hello world!
woo! mail!
*/



Incorporating into Backbone.js

As an example of how one might incorporate this extra functionality into a backbone.js app, I've adapted  Addy Osmani's standard backbone.js todoMVC application, available at http://addyosmani.github.com/todomvc/ .

To Addy's app, I've added new div consoles, unimaginatively called "Console 1" and "Console 2" at the bottom of the screen. I've set up two instances of a new View called OnScreenConsoleView as views for these consoles. Each one of the two instances subscribes to different events. The view for "Console 1", called onScreenConsoleView, will register when any of the checkboxes are clicked. The view for "Console 2" will register only when the "Mark all as Completed" checkbox is ticked.

Here's how the two console views are initialised and then setup with their respective subscriptions:

// MB - Set up the two on-screen console views.  These are our
// observers so we also set up subscriptions to the subjects in
// which they are interested: two for the first console, and one
// for the second.
var onScreenConsoleView = new OnScreenConsoleView({
   el : $("#onScreenConsole")
});
// onScreenConsoleView registers when any checkbox is clicked.                
$.Topic("toggleItemDone").subscribe(onScreenConsoleView.updateConsoleItemToggle);
$.Topic("toggleAllCompleteClicked").subscribe(onScreenConsoleView.updateConsoleAllCompleteToggle);

var onScreenConsoleView2 = new OnScreenConsoleView({
   el : $("#onScreenConsole2")
});
// onScreenConsoleView2 registers only when Mark all as complete checkbox is clicked.                
$.Topic("toggleAllCompleteClicked").subscribe(onScreenConsoleView2.updateConsoleAllCompleteToggle);



And here's an example of topic/event being published.  This is the toggleDone function from the TodoView view.  After the model is toggled (Addy's original code), I've added the $.Topic().publish line to alert an subscribers that the "toggleItemDone" event has been triggered.  I've passed the model's attributes (i.e. data) as a parameter to my subscribers' callback functions, but as the comments say, you can pass back what you like.

// Toggle the `"done"` state of the model.
toggleDone : function() {
   this.model.toggle();
   // MB - We've done the biz on our model (previous line) now do a general
   // publish to any other observers.  I'm passing back only the model
   // attributes (i.e. the data) to the observer, wrapped in an object.  You
   // can pass back the whole model if you like, or only individual attribute(s)
   // It all depends on what your observer(s) require, and where you want your
   // logic: here or in the observer?
   $.Topic("toggleItemDone").publish({attributes : this.model.attributes});
},



You can check out my modified, working version online.
You can download the source code from github.  All code is annotated with comments.  The comments for new code added by me will start with my initials, "MB".

Further reading:




Comments

1Austin  06/05/2017 1:08:02 AM  Backbone.js and jQuery pub/sub

I'm exceptionally started up to show it to absolutely every one of us. It makes me so happy your huge records and aptitude have a present day-day channel for endeavoring into the region. I'm trusting you could keep up this web site online refreshed so clients can come and investigate energizing memories. Feel free to surf (https://www.collegepaperwritingservices.com)

About