Marionette uses triggerMethod internally to trigger various
events used within the classes. This provides 'onEvent' binding
providing convenient hooks for handling class events. Notably all internally triggered events
will pass the triggering class instance as the first argument of the event.
The Application object will fire two events:
before:start eventFired just before the application is started. Use this to prepare the application with anything it will need to start, for example instantiating routers, models, and collections.
start eventFired as part of the application startup. This is where you should be showing
your views and starting Backbone.history.
import Bb from 'backbone';
import { Application } from 'backbone.marionette';
import MyModel from './mymodel';
import MyView from './myview';
const MyApp = Application.extend({
region: '#root-element',
initialize(options) {
console.log('Initialize' + options.foo);
},
onBeforeStart(app, options) {
this.model = new MyModel(options.data);
},
onStart(app, options) {
this.showView(new MyView({model: this.model}));
Bb.history.start();
}
});
const myApp = new MyApp({ foo: 'My App' });
myApp.start({ data: { bar: true } });
As shown the options object is passed into the Application as the
second argument to start.
destroy eventsThe Application class also triggers Destroy Events.
initialize eventAfter the view and behavior are constructed and initialized,
the last event to occur is an initialize event on the behavior which is passed
the view instance and any options passed to the view at instantiation.
import { Behavior, View } from 'backbone.marionette';
const MyBehavior = Behavior.extend({
onInitialize(view, options) {
console.log(options.msg);
}
});
const MyView = View.extend({
behaviors: [MyBehavior]
});
const myView = new MyView({ msg: 'view initialized' });
Note This event is unique in that the triggering class instance (the view) is not the same instance as the handler (the behavior). In most cases internally triggered events are triggered and handled by the same instance, but this is an exception.
A Behavior's view events are proxied directly on the behavior.
Note In order to prevent conflict Behavior does not trigger destroy events
with its own destruction. A destroy event occurring on the Behavior will have originated from the related view.
When you show a view inside a region - either using region.show(view) or
showChildView('region', view) - the Region will emit events around the view
events that you can hook into.
The Region class also triggers Destroy Events.
show and before:show eventsThese events fire before (before:show) and after (show) showing anything in a region.
A view may or may not be rendered during before:show, but a view will be rendered by show.
The show events will receive the region instance, the view being shown, and any options passed to region.show.
import { Region, View } from 'backbone.marionette';
const MyRegion = Region.extend({
onBeforeShow(myRegion, view, options) {
console.log(myRegion.hasView()); //false
console.log(view.isRendered()); // false
console.log(options.foo === 'bar'); // true
},
onShow(myRegion, view, options) {
console.log(myRegion.hasView()); //true
console.log(view.isRendered()); // true
console.log(options.foo === 'bar'); // true
}
});
const MyView = View.extend({
template: _.template('hello')
});
const myRegion = new MyRegion({ el: '#dom-hook' });
myRegion.show(new MyView(), { foo: 'bar' });
empty and before:empty eventsThese events fire before (before:empty) and after (empty) emptying a region's view.
These events will not fire if there is no view in the region, even if the region detaches
DOM from within the region's el.
The view will not be detached or destroyed during before:empty,
but will be detached or destroyed during the empty.
The empty events will receive the region instance, the view leaving the region.
import { Region, View } from 'backbone.marionette';
const MyRegion = Region.extend({
onBeforeEmpty(myRegion, view) {
console.log(myRegion.hasView()); //true
console.log(view.isDestroyed()); // false
},
onEmpty(myRegion, view) {
console.log(myRegion.hasView()); //false
console.log(view.isDestroyed()); // true
}
});
const MyView = View.extend({
template: _.template('hello')
});
const myRegion = new MyRegion({ el: '#dom-hook' });
myRegion.empty(); // no events, no view emptied
myRegion.show(new MyView());
myRegion.empty();
The MnObject class triggers Destroy Events.
add:region and before:add:region eventsThese events fire before (before:add:region) and after (add:region) a region is added to a view.
This event handler will receive the view instance, the region name string, and the region instance as
event arguments. The region is fully instantated for both events.
remove:region and before:remove:region eventsThese events fire before (before:remove:region) and after (remove:region) a region is removed from a view.
This event handler will receive the view instance, the region name string, and the region instance as
event arguments. The region will be not be destroyed in the before event, but is destroyed by remove:region.
Note Currently these events are only triggered using the view.removeRegion API and not when the region
is destroyed directly. https://github.com/marionettejs/backbone.marionette/issues/3602
The CollectionView triggers unique events specifically related to child management.
add:child and before:add:child eventsThese events fire before (before:add:child) and after (add:child) each child view
is instantiated and added to the children.
These will fire once for each item in the attached collection or for any view added using
addChildView.
remove:child and before:remove:child eventsThese events fire before (before:remove:child) and after (remove:child) each child view
is removed to the children.
A view may be removed from the children if it is destroyed, if it is removed
from the collection or if it is removed with removeChildView.
NOTE A childview may or may not be destroyed by this point.
NOTE When a CollectionView is destroyed it will not individually remove its children.
Each childview will be destroyed, but any needed clean up during the CollectionView's destruction
should happen in before:destroy:children.
sort and before:sort eventsThese events fire before (before:sort) and after (sort) sorting the children in the CollectionView.
These events will only fire if there are children
and a viewComparator
filter and before:filter eventsThese events fire before (before:filter) and after (filter) filtering the children in the CollectionView.
This event will only fire if there are children
and a viewFilter.
When the filter event is fired the children filtered out will have already been
detached from the view's el, but new children will not yet have been rendered.
The filter event not only receives the view instance, but also arrays of attached views,
and detached views.
const MyCollectionView = CollectionView.extend({
onBeforeFilter(myCollectionView) {
console.log('Nothing has changed yet!');
},
onFilter(myCollectionView, attachViews, detachedView) {
console.log('Array of attached views', attachedView);
console.log('Array of detached views', attachedView);
}
});
render:children and before:render:children eventsSimilar to Region show and before:show events these events fire
before (before:render:children) and after (render:children) the children of the CollectionView
are attached to the CollectionView's el or childViewContainer.
These events will be passed the CollectionView instance and the array of views being attached.
The views in the array may or may not be rendered or attached for before:render:children,
but will be rendered and attached by render:children.
If the CollectionView can determine that added views will only be appended to the end, only the appended views
will be passed to the event. Otherwise all of the children views will be passed.
Note if you consistently need all of the views within this event use children
destroy:children and before:destroy:children eventsThese events fire before (before:destroy:children) and after (destroy:children) destroying the children
in the CollectionView. These events will only fire if there are children.
The CollectionView uses a region internally that can be used to know when the empty view is show or destroyed.
See Region Events.
import { CollectionView } from 'backbone.marionette';
const MyView = CollectionView.extend({
emptyView: MyEmptyView
});
const myView = new MyView();
myView.getEmptyRegion().on({
'show'() {
console.log('CollectionView is empty!');
},
'before:empty'() {
if (this.hasView()) {
console.log('CollectionView is removing the emptyView');
}
}
});
myView.render();
render and before:render eventsReflects when a view's template is being rendered into its el.
before:render will occur prior to removing any current child views.
render is an ideal event for attaching child views to the view's template as the first
render generally occurs prior to the view attaching to the DOM.
import { View, CollectionView } from 'backbone.marionette';
import MyChildView from './MyChildView';
const MyView = View.extend({
template: _.template('<div class="foo-region"></div>'),
regions: {
'foo': '.foo-region'
},
onRender() {
this.showChildView('foo', new MyChildView());
}
});
const MyCollectionView = CollectionView.extend({
childView: MyChildView,
onRender() {
// Add a child not from the `collection`
this.addChildView(new MyChildView());
}
})
Note This event is only triggered when rendering a template into a view. A view that
is pre-rendered will not have this event triggered unless re-rendered. Pre-rendered views
should use initialize for attaching child views and the render event if the view is re-rendered.
Note If a view's template is set to false this event will not trigger.
attach and before:attach eventsRelects when the el of a view is attached to the DOM. These events will not trigger when
a view is re-rendered as the el itself does not change.
attach is the ideal event to setup any external DOM listeners such as jQuery plugins
that use the view's el, but not its contents.
detach and before:detach eventsRelects when the el of a view is detached from the DOM. These events will not trigger when
a view is re-rendered as the el itself does not change.
before:detach is the ideal event to clean up any external DOM listeners such as jQuery plugins
that use the view's el, but not its contents.
dom:refresh eventRelects when the contents of a view's el change in the DOM.
This event will fire when the view is first attached.
It will also fire if an attached view is re-rendered.
This is the ideal event to setup any external DOM listeners such as jQuery plugins
that use DOM within the el of the view and not the view's el itself.
NOTE This event will not fire if the view has no template to render unless it contains prerendered html.
dom:remove eventRelects when the contents of a view's el are about to change in the DOM.
This event will fire when the view is about to be detached.
It will also fire before an attached view is re-rendered.
This is the ideal event to clean up any external DOM listeners such as jQuery plugins
that use DOM within the el of the view and not the view's el itself.
NOTE This event will not fire if the view has no template to render unless it contains prerendered html.
Marionette is able to trigger attach/detach events down the view tree along with
triggering the dom:refresh/dom:remove events because of the view event monitor.
This monitor starts when a view is created or shown in a region (to handle non-Marionette views).
In some cases it may be a useful performance improvement to disable this functionality.
Doing so is as easy as setting monitorViewEvents: false on the view class.
import { View } from 'backbone.marionette';
const NonMonitoredView = View.extend({
monitorViewEvents: false
});
Note: Disabling the view monitor will break the monitor generated events for this view and all child views of this view. Disabling should be done carefully.
destroy and before:destroy eventsEvery class has a destroy method which can be used to clean up the instance.
With the exception of Behavior's each of these methods triggers a before:destroy
and a destroy event.
As a general rule, onBeforeDestroy is the best handler for cleanup as the instance
and any internally created children are already destroyed by the time onDestroy is called.
Note For views this is not the ideal location for clean up of anything touching the DOM.
See dom:remove or [before:detach] for DOM related clean up.
import { Application, View } from 'backbone.marionette';
const MyView = View.extend({
onBeforeDestroy(options) {
console.log(options.foo);
}
});
const myView = new MyView();
mvView.destroy({ foo: 'destroy view' });
const MyApp = Application.extend({
onBeforeDestroy(options) {
console.log(options.foo);
}
});
const myApp = new MyApp();
myApp.destroy({ foo: 'destroy app' });
CollectionView destroy:children and before:destroy:children eventsSimilar to destroy, CollectionView has events for when all of its children
are destroyed. See the CollectionView's events
for more information.
Marionette.Events and triggerMethodInternally Marionette uses triggerMethod for event triggering.
This API is not available to Backbone.Views so in order to support Backbone.Views in Marionette v4+,
Marionette.Events must be mixed into the non-Marionette view.
This can be done for an individual view definition:
import { Events } from 'backbone.marionette';
const MyBbView = Backbone.View.extend(Events);
or for all Backbone.Views
_.extend(Backbone.View.prototype, Events);
render and destroyTo support non-Marionette Views, Marionette uses two flags to determine if it should trigger
render and destroy events on the view. If a custom view throws it's own render or destroy
events, the related flag should be set to true to avoid Marionette duplicating these events.
// Add support for triggerMethod
import { Events } from 'backbone.marionette';
_.extend(Backbone.View.prototype, Events);
const MyCustomView = Backbone.View.extend({
supportsRenderLifecycle: true,
supportsDestroyLifecycle: true,
render() {
this.triggerMethod('before:render');
this.$el.html('render html');
// Since render is being triggered here set the
// supportsRenderLifecycle flag to true to avoid duplication
this.triggerMethod('render');
},
destroy() {
this.triggerMethod('before:destroy');
this.remove();
// Since destroy is being triggered here set the
// supportsDestroyLifecycle flag to true to avoid duplication
this.triggerMethod('destroy');
}
});
As mentioned in Advanced Event Settings some DOM events are triggers from the view event monitor that will handle DOM attachment related events down the view tree. Backbone View's won't have the functionality unless the monitor is added. This will include all DOM Change Events other than render.
You can add the view events monitor to any non-Marionette view:
import { monitorViewEvents, Events } from 'backbone.marionette';
// Add support for triggerMethod
_.extend(Backbone.View.prototype, Events);
const MyCustomView = Backbone.View.extend({
initialize() {
monitorViewEvents(this);
// Ideally this happens first prior to any rendering
// or attaching that might occur in the initialize
}
});