Marionette.Behavior
A Behavior
provides a clean separation of concerns to your view logic, allowing you to share common user-facing operations between your views.
Behaviors are particularly good at factoring out the common user, model and collection interactions to be utilized across your application.
Documentation Index
Using Behaviors
The easiest way to see how to use the Behavior
class is to take an example view and factor out common behavior to be shared across other views.
var Mn = require('backbone.marionette');
var MyView = Mn.View.extend({
ui: {
destroy: '.destroy-btn'
},
events: {
'click @ui.destroy': 'warnBeforeDestroy'
},
warnBeforeDestroy: function() {
alert('You are about to destroy all your data!');
this.destroy();
},
onRender: function() {
this.ui.destroy.tooltip({
text: 'What a nice mouse you have.'
});
}
});
Interaction points, such as tooltips and warning messages, are generic concepts. There is no need to recode them within your Views so they are prime candidates to be extracted into Behavior
classes.
Defining and Attaching Behaviors
var Mn = require('backbone.marionette');
var DestroyWarn = Mn.Behavior.extend({
// You can set default options
// just like you can in your Backbone Models.
// They will be overridden if you pass in an option with the same key.
defaults: {
message: 'You are destroying!'
},
ui: {
destroy: '.destroy-btn'
},
// Behaviors have events that are bound to the views DOM.
events: {
'click @ui.destroy': 'warnBeforeDestroy'
},
warnBeforeDestroy: function() {
var message = this.getOption('message');
window.alert(message);
// Every Behavior has a hook into the
// view that it is attached to.
this.view.destroy();
}
});
var ToolTip = Mn.Behavior.extend({
defaults: {
text: ''
},
ui: {
tooltip: '.tooltip'
},
onRender: function() {
this.ui.tooltip.tooltip({
text: this.getOption('text')
});
}
});
We've passed in a defaults
attribute that sets default options. This will be covered in default soon. With the warning and tooltip behaviors extracted, we just need to attach them to our view:
var Mn = require('backbone.marionette');
var MyView = Mn.View.extend({
behaviors: [DestroyWarn, ToolTip]
});
Each behavior will now be able to respond to user interactions as though the event handlers were attached to the view directly. In addition to using array notation, Behaviors can be attached using an object:
var Mn = require('backbone.marionette');
var MyView = Mn.View.extend({
behaviors: {
destroy: DestroyWarn,
tooltip: ToolTip
}
});
Behavior Options
When we attach behaviors to views, we can also pass in options to add to the behavior. This tends to be static information relating to what the behavior should do. In our above example, we want to override the message to our DestroyWarn
and Tooltip
behaviors to match the original message on the View:
var Mn = require('backbone.marionette');
var MyView = Mn.View.extend({
behaviors: [
{
behaviorClass: DestroyWarn,
message: 'You are about to destroy all your data!'
},
{
behaviorClass: ToolTip,
text: 'What a nice mouse you have.'
}
]
});
Using an object, we must define the behaviorClass
attribute to refer to our behaviors and then add any extra options with keys matching the option we want to override. Any passed options will override the defaults
passed.
Here is the syntax for declaring which behaviors get used within a View.
- You can pass behaviors either as a set of key-value pairs where the keys are used to lookup the behavior class, or as an array.
- The options for each
Behavior
are also passed through to theBehavior
during initialization. - The options are then stored within each
Behavior
underoptions
.
var Mn = require('backbone.marionette');
var MyView = Mn.View.extend({
ui: {
destroy: '.destroy-btn'
},
behaviors: {
DestroyWarn: {
message: 'you are destroying all your data is now gone!'
},
ToolTip: {
text: 'what a nice mouse you have'
}
}
});
Now let's create the DestroyWarn
Behavior
.
var Mn = require('backbone.marionette');
var DestroyWarn = Mn.Behavior.extend({
// You can set default options
// just like you can in your Backbone Models.
// They will be overridden if you pass in an option with the same key.
defaults: {
message: 'You are destroying!'
},
// Behaviors have events that are bound to the views DOM.
events: {
'click @ui.destroy': 'warnBeforeDestroy'
},
warnBeforeDestroy: function() {
alert(this.options.message);
// Every Behavior has a hook into the
// view that it is attached to.
this.view.destroy();
}
});
And onto the Tooltip
behavior.
var Mn = require('backbone.marionette');
var ToolTip = Mn.Behavior.extend({
ui: {
tooltip: '.tooltip'
},
onRender: function() {
this.ui.tooltip.tooltip({
text: this.options.text
});
}
});
Behavior Defaults
Deprecated: Defaults can be effectively set with an options
hash defined on the Behavior.
Marionette.Behavior.extend({
options: function() {
return {
deepSpace: 9
}
}
});
Marionette.Behavior.extend({
options: {
dominion: 'invasion',
doge: 'amaze'
}
});
defaults
can be a hash
or function
to define the default options for your Behavior
. The default options will be overridden depending on what you set as the options per Behavior
. (This works just like a Backbone.Model
.)
Marionette.Behavior.extend({
defaults: function() {
return {
'deepSpace': 9
}
}
});
Marionette.Behavior.extend({
defaults: {
'dominion': 'invasion',
'doge': 'amaze'
}
});
view
The view
is a reference to the View
instance that the Behavior
is attached to.
Marionette.Behavior.extend({
handleDestroyClick: function() {
this.view.destroy();
}
});
Nesting Behaviors
In addition to extending a View
with Behavior
, a Behavior
can itself use other Behaviors. The syntax is identical to that used for a View
:
var Mn = require('backbone.marionette');
var Modal = Mn.Behavior.extend({
behaviors: {
DestroyWarn: {
message: 'Whoa! You sure about this?'
}
}
});
Nested Behaviors act as if they were direct Behaviors of the parent Behavior
's view instance.
View Proxy
The Behavior
class provides proxies for a selection of View
functionality. This includes listening to events on the view, being able to handle events on models and collections, and being able to directly interact with the attached template.
Listening to View Events
Behaviors are powered by an event proxy. This means that any events that are triggered on a View
are passed to all attached behaviors
. This includes:
- Events fired by
triggerMethod
- Events fired from
triggers
- Events fired by
childViewTriggers
- Events fired from
childView
These handlers work exactly as they do on View
- see the View
documentation
Events triggered in the behavior instance are not executed in the view. To notify the view, the behavior must trigger an event in its view property, e.g,
this.view.trigger('my:event')
Proxy Handlers
Behaviors provide proxies to a number of the view event handling attributes including:
Events / Initialize Order
If both view and behavior are listening for the same event, this will be executed first in the view then in the behavior as below.
The View + Behavior initialize process is as follows:
- View is constructed
- Behavior is constructed
- Behavior is initialized with view property set
- View is initialized
- View triggers an
initialize
event on the behavior.
This means that the behavior can access the view during its own initialize
method. The view initialize
is called later with the information eventually injected by the behavior. The initialize
event is triggered on the behavior indicating that the view is fully initialized.
Using ui
As in views, events
and triggers
can use the ui
references in their listeners. For more details, see the ui
documentation for views. These can be defined on either the Behavior or the View:
var Mn = require('backbone.marionette');
var MyBehavior = Mn.Behavior.extend({
ui: {
saveForm: '.btn-save'
},
events: {
'click @ui.saveForm': 'saveForm'
},
modelEvents: {
invalid: 'showError'
},
saveForm: function() {
this.view.model.save();
},
showError: function() {
alert('You have errors');
}
});
If your ui
keys clash with keys on the attached view, references within the behavior will always use the definition on the behavior itself. As views are only peripherally aware of their behaviors, their ui
keys will not be changed when accessed within the View
. For example:
var Mn = require('backbone.marionette');
var MyBehavior = Mn.Behavior.extend({
ui: {
saveForm: '.btn-save'
},
events: {
'click @ui.saveForm': 'saveForm' // .btn-save
},
saveForm: function() {
this.view.model.save();
}
});
var FirstView = Mn.View.extend({
behaviors: [MyBehavior],
ui: {
saveForm: '.btn-primary'
},
events: {
'click @ui.saveForm': 'checkForm' // .btn-primary
},
checkForm: function() {
// ...
}
});
View and el
The Behavior
has a number of proxies attributes that directly refer to the related attribute on a view:
$
el
$el
In addition, each behavior is able to reference the view they are attached to through the view
attribute:
var Mn = require('backbone.marionette');
var ViewBehavior = Mn.Behavior.extend({
onRender: function() {
if (this.view.model.get('selected')) {
this.$el.addClass('highlight');
}
else {
this.$el.removeClass('highlight');
}
}
});
© 2017 Muted Solutions, LLC
Licensed under the MIT License.
https://marionettejs.com/docs/v3.5.1/marionette.behavior.html