Backbone JS: can one view trigger updates in other views?

Solution 1:

You might want to have a read of this discussion of Backbone pub/sub events:

http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/

I like to add it in as a global event mechanism:

Backbone.pubSub = _.extend({}, Backbone.Events);

Then in one view you can trigger an event:

Backbone.pubSub.trigger('my-event', payload);

And in another you can listen:

Backbone.pubSub.on('my-event', this.onMyEvent, this);

Solution 2:

I use what Addy Osmani calls the mediator pattern http://addyosmani.com/largescalejavascript/#mediatorpattern. The whole article is well worth a read.

Basically it is an event manager that allows you to subscribe to and publish events. So your AppView would subscript to an event, i.e. 'selected'. Then the BrandView would publish the 'selected' event.

The reason I like this is it allows you to send events between views, without the views being directly bound together.

For Example

var mediator = new Mediator(); //LOOK AT THE LINK FOR IMPLEMENTATION

var BrandView = Backbone.View.extend({
    toggle_select: function() {
        ...
        mediator.publish('selected', any, data, you, want);
        return this;
    }
});

var AppView = Backbone.View.extend({
    initialize: function() {
        mediator.subscribe('selected', this.delete_selected)
    },

    delete_selected: function(any, data, you, want) {
        ... do something ...
    },
});

This way your app view doesn't care if it is a BrandView or FooView that publishes the 'selected' event, only that the event occured. As a result, I find it a maintainable way to manage events between parts of you application, not just views.

If you read further about the 'Facade', you can create a nice permissions structure. This would allow you to say only an 'AppView' can subscribe to my 'selected' event. I find this helpful as it makes it very clear where the events are being used.

Solution 3:

Ignoring the problems with this that you already mention in your post, you can bind and trigger events to/from the global Backbone.Event object, which will allow anything to talk to anything else. Definitely not the best solution, and if you have views chatting with one another then you should consider refactoring that. But there ya go! Hope this helps.

Solution 4:

Here is my case with a similar need: Backbone listenTo seemed like a solution to redirect to login page for timed out or not authenticated requests.

I added event handler to my router and made it listen to the global event such as:

Backbone.Router.extend({
    onNotAuthenticated:function(errMsg){
        var redirectView = new LoginView();
        redirectView.displayMessage(errMsg);
        this.loadView(redirectView);
    },
    initialize:function(){
        this.listenTo(Backbone,'auth:not-authenticated',this.onNotAuthenticated);  
    },
    .....
});

and in my jquery ajax error handler:

$(document).ajaxError(
    function(event, jqxhr, settings, thrownError){
        .......
        if(httpErrorHeaderValue==="some-value"){
             Backbone.trigger("auth:not-authenticated",errMsg);
        }
    });     

Solution 5:

You can use Backbone object as the event bus.

This approach is somewhat cleaner but still relies on Global Backbone object though

var view1 = Backbone.View.extend({

  _onEvent : function(){
    Backbone.trigger('customEvent');
  }

});


var view2 = Backbone.View.extend({

  initialize : function(){
    Backbone.on('customEvent', this._onCustomEvent, this);
  },

  _onCustomEvent : function(){
    // react to document edit.
  }

});