In addition to what Backbone provides the views, Marionette has additional API for DOM interactions available to all Marionette view classes.
Marionette's Views extend Backbone.View
and
so have references to the view's el
, $el
, and this.$()
as well as
defining an events
hash.
These methods provide ways for interacting with the view scoped to it's el
and all of the view's children. To restate events
and this.$()
will query
the view's template and all of the children. Marionette's added interfaces
attempt to scope interactions with only the view's template, leaving the
children to handle themselves.
Views can bind custom events whenever users perform some interaction with the
DOM. Using the view events
and triggers
handlers lets us either bind user input directly to an action or fire a generic
trigger that may or may not be handled.
The events
and triggers
attributes bind DOM events to actions to perform on
the view. They each take a DOM event key and a mapping to the handler.
We'll cover a simple example:
import { View } from 'backbone.marionette';
const MyView = View.extend({
events: {
'drop': 'onDrop',
'click .btn-show-modal': 'onShowModal',
'click @ui.save': 'onSave'
},
triggers: {
'click @ui.close': 'close'
},
ui: {
save: '.btn-save',
close: '.btn-cancel'
},
onShowModal() {
console.log('Show the modal');
},
onSave() {
console.log('Save the form');
},
onDrop() {
console.log('Handle a drop event anywhere in the element');
}
});
Event listeners are constructed by:
'<dom event> [dom node]': 'listener'
The dom event
can be a jQuery DOM event - such as click
- or another custom
event, such as Bootstrap's show.bs.modal
.
The dom node
represents a jQuery selector or a ui
key prefixed by @.
.
The dom node
is optional, and if omitted, the view's $el
will be used as the
selector. For more information about the ui
object, and how it works, see
the documentation on ui.
events
The view events
attribute binds DOM events to functions or methods on the
view. The simplest form is to reference a method on the view:
import { View } from 'backbone.marionette';
const MyView = View.extend({
events: {
'click a': 'onShowModal'
},
onShowModal(event) {
console.log('Show the modal');
}
});
The DOM event gets passed in as the first argument, allowing you to see any information passed as part of the event.
When passing a method reference, the method must exist on the View.
The events
attribute can also directly bind functions:
import { View } from 'backbone.marionette';
const MyView = View.extend({
events: {
'click a'(event) {
console.log('Show the modal');
}
}
});
As when passing a string reference to a view method, the events
attribute
passes in the event
as the argument to the function called.
Note Backbone events
are delegated to the view's el
. This means that
events with a dom node selector will be handled for the view and any decendants.
So if you attach a child with the same selector as the parent event handler, the
parent will handle the event for both views.
triggers
The view triggers
attribute binds DOM events to Marionette events that
can be responded to at the view or parent level. For more information on events,
see the events documentation. This section will just
cover how to bind these events to views.
import { View } from 'backbone.marionette';
const MyView = View.extend({
triggers: {
'click a': 'click:link'
},
onClickLink(view, event) {
console.log('Show the modal');
}
});
When the a
tag is clicked here, the link:click
event is fired. This event
can be listened to using the onEvent
Binding
technique discussed in the events documentation.
The major benefit of the triggers
attribute over events
is that triggered
events can bubble up to any parent views. For a full explanation of bubbling
events and listening to child events, see the
event bubbling documentation..
triggers
Event ObjectEvent handlers will receive the triggering view as the first argument and the DOM Event object as the second followed by any extra parameters triggered by the event.
NOTE It is strongly recommended that View's handle their own DOM event objects. It should be considered a best practice to not utilize the DOM event in external listeners.
By default all trigger events are stopped with preventDefault
and stopPropagation
methods. This by nature artificially
scopes event handling to the view's template preventing event handling of the same selectors in
child views. However you can manually configurethe triggers using a hash instead of an event name.
The example below triggers an event and prevents default browser behaviour using preventDefault
.
import { View } from 'backbone.marionette';
const MyView = View.extend({
triggers: {
'click a': {
event: 'link:clicked',
preventDefault: true, // this param is optional and will default to true
stopPropagation: false
}
}
});
The default behavior for calling preventDefault
can be changed with the feature flag
triggersPreventDefault
, and stopPropagation
can be changed with the feature flag triggersStopPropagation
.
The View
provides a mechanism to name parts of your template to be used
throughout the view with the ui
attribute. This provides a number of benefits:
ui
To define your ui
hash, just set an object of named jQuery selectors to the
ui
attribute of your View:
import { View } from 'backbone.marionette';
const MyView = View.extend({
template: MyTemplate,
ui: {
save: '#save-button',
close: '.close-button'
}
});
Inside your view, the save
and close
references will point to the jQuery
selectors #save-button
and .close-button
respectively found only in the
rendered MyTemplate
.
To get the handles to your UI elements, use the getUI(ui)
method:
import { View } from 'backbone.marionette';
const MyView = View.extend({
template: MyTemplate,
ui: {
save: '#save-button',
close: '.close-button'
},
onFooEvent() {
const $saveButton = this.getUI('save');
$saveButton.addClass('disabled');
$saveButton.attr('disabled', 'disabled');
}
});
As $saveButton
here is a jQuery selector, you can call any jQuery methods on
it, according to the jQuery documentation.
events
and triggers
The UI attribute is especially useful when setting handlers in the
events
and triggers
objects - simply use
the @ui.
prefix:
import { View } from 'backbone.marionette';
const MyView = View.extend({
template: MyTemplate,
ui: {
save: '#save-button',
close: '.close-button'
},
events: {
'click @ui.save': 'onSave'
},
triggers: {
'click @ui.close': 'close'
},
onSave() {
this.model.save();
}
});
In this example, when the user clicks on #save-button
, onSave
will be
called. If the user clicks on .close-button
, then the event close:view
will
be fired on MyView
.
By prefixing with @ui
, we can change the underlying template without having to
hunt through our view for every place where that selector is referenced - just
update the ui
object.