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 attach
ed.
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 detach
ed.
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 triggerMethod
Internally Marionette uses triggerMethod
for event triggering.
This API is not available to Backbone.View
s so in order to support Backbone.View
s 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.View
s
_.extend(Backbone.View.prototype, Events);
render
and destroy
To 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
}
});