Search code examples
javascriptbackbone.jstriggersmarionette

Backbone: LayoutView needs to listenTo a ItemView inside a CollectionView


I'm trying to use the listenTo method in Backbone to listen to a trigger that is inside a child view, inside a collection view, and up to the collection views parent LayoutView.

From google searches a lot people mentioned to use a library for nested objects in backbone, but I'm trying to work out what the standard way of doing it is.

Just to be clearer, my question is: How can I make the trigger in my childView (ItemDetailsView) bubble up to the parent LayoutView (MyItemsList.Layout)

      var ItemDetailsView = Backbone.Marionette.LayoutView.extend({
          template: JST["items/item"],
          tagName: "li",
          className: "item",

          events: {
              "click @ui.btn": "callTrigger"
          },

          callTrigger: function() {
               this.trigger("hello:world");
           }
      )}; 

      var ItemListView = Backbone.Marionette.CollectionView.extend({
           tagName: "ul",
           childView: itemDetailsView
       });

      MyItemsList.Layout = Marionette.LayoutView.extend({
          template: JST["items/current-items"],
          tagName: "section",
          className: "current-items",

          onShow: function() {
               var listCollection = this.model.currentListCollection;
               var listView = new MyListView({
                    collection: listCollection
               });

               this.listenTo(listView.collection, "hello:world", _.bind(function() {
                    console.log("I heard that!")
               }, this));
          }

       });

Solution

  • Use childEvents property of CollectionView (http://marionettejs.com/docs/v2.3.2/marionette.collectionview.html#collectionviews-childevents).

    Your code could be then written as follows.

      var ItemDetailsView = Backbone.Marionette.LayoutView.extend({
          template: JST["items/item"],
          tagName: "li",
          className: "item",
    
          events: {
              "click @ui.btn": "callTrigger"
          },
    
          callTrigger: function() {
               this.trigger("hello:world");
           }
      )}; 
    
      var ItemListView = Backbone.Marionette.CollectionView.extend({
           tagName: "ul",
           childView: itemDetailsView,
           // This callback will be called whenever a child is rendered or emits a `render` event
           childEvents: {
              "hello:world": function() {
                console.log("a childView said hello world!");
                this.triggerMethod('child:hello:world');
              }
            }
       });
    
      MyItemsList.Layout = Marionette.LayoutView.extend({
          template: JST["items/current-items"],
          tagName: "section",
          className: "current-items",
    
          onShow: function() {
               var listCollection = this.model.currentListCollection;
               var listView = new MyListView({
                    collection: listCollection
               });
    
               this.listenTo(listView, "child:hello:world", _.bind(function() {
                    console.log("I heard that!")
               }, this));
          }
    
       });