32

I'm working on a Backbone app that contains a list of entries, much like the example app Todos (http://documentcloud.github.com/backbone/examples/todos/index.html).

So, I have an App view and one view per list item. Now, say I have a global edit button. The App view would handle a click and what I then want to do is tell each list view to show a delete button.

In the screenshots below (from Spotify), pressing the Edit button causes all list views to change appearance.

What's the best way to do this with Backbone. I need to iterate over all list views and call a editMode function. But the App view (out of the box) doesn't know about the list views..

enter image description here

Sebastian
  • 891
  • 2
  • 11
  • 19
  • 3
    I came here to ask this exact same question and happened to see yours on my front page... spooky. – aw crud Sep 20 '11 at 13:49

2 Answers2

41

I wrote up an article a while back on a few different options for coordinating between views: http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/

in your case, i'd recommend using the event aggregator that i describe in that article. you could have each item view listen for a "editmode" event, or something similar. when this event fires, each view that listened for it would update itself to go into edit mode. then you would do the opposite when you click "done" - send a "viewmode" event, or something similar, and have each view update itself appropriately.

Derick Bailey
  • 72,004
  • 22
  • 206
  • 219
  • 1
    Assume that, for the example in the question, each track's view has a reference to the collection of tracks. Either directly or through a property of the track model backing each track view. Would it be wrong to send 'editmode' events through this collection? That way you don't need a separate event object to facilitate this. – aw crud Sep 20 '11 at 15:10
  • 1
    "wrong" is very subjective. it depends on the complexity involved in your app, and how far down the path of decoupling your app needs to go. you might start by passing it through the collection and see if that works for you. if you start seeing everything too tightly coupled, then restructure to use a separate event object. – Derick Bailey Sep 20 '11 at 16:09
  • @DerickBailey - really like the pattern you describe in your article. Thanks for sharing. – UpTheCreek Oct 03 '11 at 06:22
  • 6
    Thurloat from Sheepdog posted a really inspiring extension to your solution, where he recommends the use of a **view factory**. His suggestion allows 1) to eliminate the need to explicitly pass the eventBus to each view (or declare the eventBus global) and 2) to declare global event binding in the declarative backbone way, which is a huge improvement towards readability. Here is the complete article http://thurloat.com/2012/01/21/backbonejs-readable-modular-testable-views - which is in coffeescript – SunnyRed Feb 03 '12 at 14:34
  • I had similar problem and like your Event Aggregator idea. tnx – zsitro Oct 18 '12 at 07:36
  • Derick what are your thoughts on using your Backbone.Babysitter library for this purpose? Obviously the list view would have to use babysitter, but taken that as a given, seems very clean to proxy a "setMode" method on the list to each of the individual list item views, using babysitter's "call" method. – Brave Dave Jan 16 '13 at 03:44
2

My two cents: There is a simple "hack" you can do with backbone.js to actually have a pub/sub that can communicate between views:

Something along these lines (untested):

var EventBus = Backbone.Model.extend({

   publish: function(event, args){

       this.trigger(event, args);

   },

   subscribe: function(event, args) {

       this.bind(event, args);

   }
});

You basically get the idea. Now for every view, have it 'bind' to this EventBus (since views can only bind to models/collections in backbone) - you basically just use the method names publish/subscribe to be in sync with the nomenclature of such a model but you may choose not to. Just create an empty EventBus 'class' in that case and have every view bind to it :)

So every view only needs to be coupled to this EventBus and act on received events! Backbone.js internally handles all the plumbing of this design pattern, so you pretty much get it for free :)

The above code may not run as-is, but is there to give you an idea about it...

Casey Flynn
  • 13,654
  • 23
  • 103
  • 194
PhD
  • 11,202
  • 14
  • 64
  • 112
  • 1
    There is Backbone.Events already, so why not keep things DRY? – opengrid Oct 11 '12 at 18:35
  • @opengrid - this was for v0.5.1. when it "how to use the Events" was not as well advertised :) – PhD Oct 11 '12 at 20:03
  • 1
    Saying, "You basically get the idea" instead of clearly explaining what you mean isn't very useful, and may be more frustrating than helpful for people who are trying to find an answer. – Pea Jun 11 '15 at 16:19