I implemented a solution for a similar problem as follows. First, I wrote a new method right into the Marionette.View prototype:
Marionette.View.prototype.bubbleMethod = function () {
var args = _.toArray(arguments)
var event = args.shift()
var bubble = event + ':bubble'
this.triggerMethod.apply(this, [ event ].concat(args))
this.triggerMethod.apply(this, [ bubble ].concat(args))
}
That will call the regular triggerMethod
from Marionette twice: once with your event name as it is intended to be handled, and a second one which is easily recognizable by specialized views, designated to bubble events up.
Then you will need such specialized view and bubble up events that are meant to be bubbled up. You must be careful not to dispatch events like close
(or any Marionette events at all) in behalf of other views, because that will cause all sorts of unpredictable behaviors in Regions and Views. The :bubble
suffix allows you to easily recognize what's meant to bubble. The bubbling view might look like this:
var BubblingLayout = Marionette.Layout.extend({
handleBubbles: function (view) {
var bubble = /:bubble$/
this.listenTo(view, 'all', function () {
var args = _.toArray(arguments)
var event = args.shift()
if (event.match(bubble)) {
event = event.replace(bubble, '')
this.bubbleMethod.apply(this, [ event ].concat(args))
}
}, this)
}
})
The last thing you need to make sure is to be able to bubble events across regions (for Layouts and modules with custom region managers). That can be handled with the show
event dispatches from a region, like this:
var BubblingLayout = Marionette.Layout.extend({
regions: {
sidebar: '#sidebar'
},
initialize: function () {
this.sidebar.on('show', this.handleBubbles, this)
},
handleBubbles: function (view) {
var bubble = /:bubble$/
this.listenTo(view, 'all', function () {
var args = _.toArray(arguments)
var event = args.shift()
if (event.match(bubble)) {
event = event.replace(bubble, '')
this.bubbleMethod.apply(this, [ event ].concat(args))
}
}, this)
}
})
The last part is to make something actually bubble up, which is easily handled by the new bubbleMethod
method:
var MyView = Marionette.ItemView.extend({
events: {
'click': 'clickHandler'
},
clickHandler: function (ev) {
// do some stuff, then bubble something else
this.bubbleMethod('stuff:done')
}
})
var BubblingLayout = Marionette.Layout.extend({
regions: {
sidebar: '#sidebar'
},
initialize: function () {
this.sidebar.on('show', this.handleBubbles, this)
},
onRender: function () {
var view = new MyView()
this.sidebar.show(view)
},
handleBubbles: function (view) {
var bubble = /:bubble$/
this.listenTo(view, 'all', function () {
var args = _.toArray(arguments)
var event = args.shift()
if (event.match(bubble)) {
event = event.replace(bubble, '')
this.bubbleMethod.apply(this, [ event ].concat(args))
}
}, this)
}
})
Now you can handle bubbled events from any place in your code where you can access an instance of BubblingLayout
.