4
votes

Using MarionetteJS v1.0.3.

I have a instance of a Marionette.Layout which has two regions.

The first region is a CompositeView on the left, the other region is a ItemView on the right.

The CompositeView renders multiple ItemViews.

The idea is, the user clicks on one of the items in the collection on the left, to display the selected record in full on the ItemView on the right.

How can the Layout at the top subscribe to the events in the chain: Layout > Region > CompositeView > ItemView

As the Layout at the top is the only one aware of the detailed region to the right, the event needs to be consumed here all the way from the CompositeView where the click event would be triggered. I know there are global events, but they are global, and there might be multiple Layouts running at once so their events would collide.

LeftListPanelView = Marionette.CompositeView.extend({

    template: "#leftPanel",
    itemViewContainer: "ul",

    events: {
        "click li": "rowClicked"
    },

    rowClicked: function (e) {
        var itemid = $(e.currentTarget).data("itemid") * 1;
        var selectedItem = this.collection.get(itemid);

        if (selectedItem) {
            this.trigger("itemSelected", selectedItem);
        }
    }
});
2
I think the click event triggered by the list item should bubble all the way up the DOM hierarchy to the element associated with your Marionette Layout. Therefore, I think you could handle the event in the layout rather than in your LeftListPanelView using exactly the same code. Obviously that assumes the layout view has a reference to the collection.net.uk.sweet

2 Answers

7
votes

Just use events. When a user clicks on an item trigger an event with MyApp.trigger("item:clicked", myItemInstance). Then, in your layout, simply listen to the event with

MyApp.on("item:clicked", function(myItemInstance){
   // do stuff
});

Note you can also "automatically" have triggered events from an itemView bubble up to a collection/composite view (see https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md#itemview-event-bubbling-from-child-views)

You can see an example of using events to control your app's behavior here: https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/list/list_controller.js

That code is extracted from the book I'm writing on Marionette: https://leanpub.com/marionette-gentle-introduction (free sample here: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf)

10
votes

In short, you can bind to that event after showing your CompositeView on your Layout with:

yourLayout.region.currentView.on('item:clicked', yourFunction);

This is a much better solution than using global events. Global events work for the semantic reasoning of saying "this is event that is globally related to the state of my application" and (in my opinion) actually represent an anti-pattern that only needs used when project architecture has become a mess and needs refactoring.

The best approach with events is always to trigger an event from the object that it occured within, and to always watch events on the objects triggering them.