## File: readme.md
Marionette.js
# Marionette v5
Marionette is dropping its dependency on Backbone. That library is available here: https://github.com/marionettejs/marionette
Until further notices changes to `backbone.marionette` will be limited to fixes. All new feature work will take place on `marionette`.
## Marionette v4
Marionette 4 is now available! See our
[upgrade notes](https://marionettejs.com/docs/v4.0.0/upgrade-v3-v4.html) for the differences between
v3 and v4. Please let us know if you encounter any issues so we can resolve
them and
[help us continue work on Marionette!](https://github.com/marionettejs/backbone.marionette/milestones/v4.x)
## About Marionette
Marionette is a composite application library for Backbone.js that
aims to simplify the construction of large scale JavaScript applications.
It is a collection of common design and implementation patterns found in
applications.
## Documentation
All of the documentation for Marionette can be found at
##### [marionettejs.com/docs/current](http://marionettejs.com/docs/current)
### App Architecture On Backbone's Building Blocks
Backbone provides a great set of building blocks for our JavaScript
applications. It gives us the core constructs that are needed to build
small apps, organize jQuery DOM events, or create single page apps that
support mobile devices and large scale enterprise needs. But Backbone is
not a complete framework. It's a set of building blocks. It leaves
much of the application design, architecture and scalability to the
developer, including memory management, view management, and more.
Marionette brings an application architecture to Backbone, along with
built in view management and memory management. It's designed to be a
lightweight and flexible library of tools that sits on top of Backbone,
providing the framework for building a scalable application.
Like Backbone itself, you're not required to use all of Marionette just
because you want to use some of it. You can pick and choose which features
you want to use. This allows you to work with other Backbone
frameworks and plugins easily. It also means that you are not required
to engage in an all-or-nothing migration to begin using Marionette.
### Chat with us
Find us [on gitter](https://gitter.im/marionettejs/backbone.marionette).
We're happy to discuss design patterns and learn how you're using Marionette.
### Key Benefits
* Scalable: applications built in modules with event-driven architecture
* Sensible defaults: Underscore templates are used for view rendering
* Easily modifiable: works with the specific needs of your application
* Reduce boilerplate: for all views, including specialized types
* Create: application visuals at runtime with `Region` and `View` objects
* Nested: `View`s and `CollectionView`s within visual regions
* Built-in: memory management and zombie-killing for `View`s, `CollectionViews`a and `Region`s
* Event-driven architecture: utilizing `Backbone.Radio`
* Flexible: "as-needed" architecture allowing you to pick and choose what you need
* And much, much more
## Source Code and Downloads
You can
[download the latest builds directly](https://github.com/marionettejs/backbone.marionette/tree/master/lib)
or visit the [downloads section on the Marionette website](http://marionettejs.com#download)
for more downloading options.
#### [MarionetteJS.com](http://marionettejs.com#download)
### NPM and Bower
Marionette is available via bower and npm:
```bash
# NPM
npm install backbone.marionette
# Bower
bower install marionette
```
## Release Notes And Upgrade Guide
**Changelog**: For change logs and release notes, see the
[changelog](changelog.md) file.
**Upgrade Guide**: Be sure to read [the upgrade guide](upgradeGuide.md)
for information on upgrading to the latest version of Marionette.
### Annotated Source Code
The source code for Marionette is heavily documented.
You can read the annotations for all the details of how Marionette works and advice on which methods to override.
##### [View the annotated source code](http://marionettejs.com/annotated-src/backbone.marionette)
## Compatibility and Requirements
MarionetteJS currently works with the following libraries:
* [jQuery](http://jquery.com) v1.8+
* [Underscore](http://underscorejs.org) v1.8.3 - v1.9.x
* [Backbone](http://backbonejs.org) v1.3.3
* [Backbone.Radio](https://github.com/marionettejs/backbone.radio) v2.0.0+
Marionette has not been tested against any other versions of these
libraries. You may or may not have success if you use a version other
than what is listed here.
## How to Contribute
If you would like to contribute to Marionette's source code, please read
the [guidelines for pull requests and contributions](CONTRIBUTING.md).
Following these guidelines will help make your contributions easier to
bring into the next release.
### [Github Issues](https://github.com/marionettejs/backbone.marionette/issues)
Report issues with Marionette, submit pull requests to fix problems, or to
create summarized and documented feature requests (preferably with pull
requests that implement the feature).
---
## File: docs/backbone.radio.md
# Backbone Radio
The Backbone Radio provides easy support for a number of messaging patterns for
Backbone and Marionette. This is provided through two basic constructs:
* Events - trigger events on a global object
* Requests - a global request/reply implementation
Radio takes these two constructs and adds the channel implementation - providing
namespaces for events and requests. In short, Radio is a global, namespaced,
message bus system designed to allow two otherwise unrelated objects to
communicate and share information.
## Documentation Index
* [Radio Concepts](#radio-concepts)
* [Channel](#channel)
* [Event](#event)
* [When to use Events](#when-to-use-events)
* [Request](#request)
* [Returning Values from Reply](#returning-values-from-reply)
* [When to use Requests](#when-to-use-requests)
* [Marionette Integration](#marionette-integration)
* [API](#api)
* [Examples](#examples)
* [Listening to Events](#listening-to-events)
* [Replying to Requests](#replying-to-requests)
* [Events and Requests](#events-and-requests)
## Radio Concepts
The `Radio` message bus exposes some core concepts:
* `Channel` - a namespace mechanism.
* `Event` - alert other parts of your application that something happened.
* `Request` - execute single functions in a different part of your application.
### Channel
The `channel` is the biggest reason to use `Radio` as our event aggregator - it
provides a clean point for dividing global events. To retrieve a channel, use
`Radio.channel(channelName)`:
```javascript
import Radio from 'backbone.radio';
const myChannel = Radio.channel('basic');
myChannel.on('some:event', function() {
// ...
});
```
The channel is accessible everywhere in your application. Simply import Radio
and call `channel()` to add listeners, fire callbacks, or send requests.
```javascript
import Radio from 'backbone.radio';
const someChannel = Radio.channel('basic'); // Exactly the same channel as above
someChannel.trigger('some:event'); // Will fire the function call above
```
[Live example](https://jsfiddle.net/marionettejs/0bejfju0/)
### Event
The `Radio Event` works exactly the same way as regular `Backbone Events`
like model/collection events. In fact, it uses the `Backbone.Events` mixin
internally, exposing its API:
* `channel.on('event', callback, [context])` - when `event` fires, call `callback`
* `channel.once('event', callback, [context])` - same as `on`, but triggered only once
* `channel.off('event')` - stop listening to event
* `channel.trigger('event', ..args)` - fires `event` and passes args into the
resulting `callback`
Events are typically used to alert other parts of the system that something
happened. For example, a user login expired or the user performed a specific
action.
As the Radio can be imported anywhere, we can use it as a global event
aggregator as such:
```javascript
import Radio from 'backbone.radio';
const myChannel = Radio.channel('star');
myChannel.on('left:building', function(person) {
console.log(person.get('name') + ' has left the building!');
});
const elvis = new Bb.Model({name: 'Elvis'});
myChannel.trigger('left:building', elvis);
myChannel.off('left:building');
```
Just like Backbone Events, the Radio respects the `listenTo` handler as well:
```javascript
import { MnObject } from 'backbone.marionette';
import Radio from 'backbone.radio';
const starChannel = Radio.channel('star');
const Star = MnObject.extend({
initialize() {
this.listenTo(starChannel, 'left:building', this.leftBuilding);
this.listenTo(starChannel, 'enter:building', function(person) {
console.log(person.get('name') + ' has entered the building!');
});
},
leftBuilding(person) {
console.log(person.get('name') + ' has left the building!');
}
});
```
Note that the event handler can be defined as a method like used for
`'left:building'` event or inline like used in `'enter:building'`.
[Live example](https://jsfiddle.net/marionettejs/s8nff8vz/)
As in Backbone, the event handler is called with `this` bound to the `Star` instance. See the
[Backbone documentation](http://backbonejs.org/#Events) for the full list of
Event handling methods.
#### When to use Events
The Event is a simple notification that _something happened_ and you may or may
not want other objects in your application to react to that. A few key
principles to bear in mind are:
* If you don't know what could act on the event, or don't care, use an `Event`
* If you find yourself calling it an action that occurred, use an `Event`
* If it's fine for many objects to perform an action, use an `Event`
* If you don't mind that no objects react, use an `Event`
If your use case isn't covered here, consider whether you want to
[use a request](#when-to-use-requests) instead.
### Request
The Request API provides a uniform way for unrelated parts of the system to
communicate with each other. For example, displaying notifications in response
to system activity. To attach a listener to a request channel, use `reply` or
`replyOnce` to attach a listener that immediately detaches after one call.
As with request, any arguments passed in `channel.request` will be passed into
the callback.
```javascript
import { MnObject } from 'backbone.marionette';
import Radio from 'backbone.radio';
const channel = Radio.channel('notify');
const Notification = MnObject.extend({
initialize() {
channel.reply('show:success', this.showSuccessMessage);
channel.reply('show:error', function(msg) {
// ...
});
},
showSuccessMessage(msg) {
// ...
}
});
```
So, for example, when a model sync fails:
```javascript
import { View } from 'backbone.marionette';
import Radio from 'backbone.radio';
const channel = Radio.channel('notify');
const ModelView = View.extend({
modelEvents: {
error: 'showErrorMessage'
},
showErrorMessage() {
channel.request('show:error', 'An error occurred contacting the server');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/4uuyLe1q/)
Now, whenever the model attached to this View is unable to sync with the server,
we can display an error message to the user.
### Returning Values from Reply
The Request API is also able to return values, making it extremely useful for
accessing objects that would be otherwise difficult to access. As an example,
let's assume we attach the currently logged-in user to the `Application` object
and we want to know if they're still logged-in.
```javascript
import { Application } from 'backbone.marionette';
import Radio from 'backbone.radio';
const channel = Radio.channel('user');
const App = Application.extend({
initialize() {
channel.reply('user:loggedIn', this.isLoggedIn);
},
isLoggedIn() {
return this.model.getLoggedIn();
}
});
```
Then, from another view, instead of trying to find the User model. we simply
`request` it:
```javascript
const Radio = require('backbone.radio');
const channel = Radio.channel('user');
const loggedIn = channel.request('user:loggedIn'); // App.model.getLoggedIn()
```
[Live example](https://jsfiddle.net/marionettejs/zaje1rLj/)
### When to use Requests
A Request is, as you might guess, a request for information or for something to
happen. You will probably want to use requests when:
* You call the request an action to perform e.g. `show:notification`
* You want to get the return value of the request
* You want to call _exactly one_ function
In addition to this documentation, the Radio documentation can be found on
[Github](https://github.com/marionettejs/backbone.radio).
## Marionette Integration
The [`Application`](./marionette.application.md) and [`MnObject`](./marionette.mnobject.md) classes
provide bindings to provide automatic event listeners and / or request handlers on your object
instances. This works with a bound `channelName` to let us provide listeners using the `radioEvents`
and `radioRequests` properties.
**Errors** An error will be thrown if using the radio integration unless `backbone.radio` is setup
as a dependency.
### API
* `channelName` - defines the Radio channel that will be used for the requests and/or events
* `getChannel()` - returns a Radio.Channel instance using `channelName`
* `radioEvents` - defines an events hash with the events to be listened and its respective handlers
* `radioRequests` - defines an events hash with the requests to be replied and its respective handlers
### Examples
#### Listening to events
```javascript
import { MnObject } from 'backbone.marionette';
const Star = MnObject.extend({
channelName: 'star',
radioEvents: {
'left:building': 'leftBuilding'
},
leftBuilding(person) {
console.log(person.get('name') + ' has left the building!');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/tf9467x4/)
This gives us a clear definition of how this object interacts with the `star`
radio channel.
#### Replying to requests
```javascript
import { MnObject } from 'backbone.marionette';
const Notification = MnObject.extend({
channelName: 'notify',
radioRequests: {
'show:success': 'showSuccessMessage',
'show:error': 'showErrorMessage'
},
showSuccessMessage(msg) {
// ...
},
showErrorMessage(msg) {
// ...
}
});
```
[Live example](https://jsfiddle.net/marionettejs/j2qgfk3s/)
We now have a clear API for communicating with the `Notification` across the
application. Don't forget to define the `channelName` on your `MnObject`
definition.
As with a normal request/reply, we can return values from these bound handlers:
```javascript
import { Application } from 'backbone.marionette';
const App = Application.extend({
channelName: 'user',
radioRequests: {
'user:loggedIn': 'isLoggedIn'
},
isLoggedIn() {
return this.model.getLoggedIn();
}
});
```
[Live example](https://jsfiddle.net/marionettejs/52rpd3zg/)
#### Events and requests
```javascript
import { MnObject } from 'backbone.marionette';
const NotificationHandler = MnObject.extend({
channelName: 'notify',
radioRequests: {
'show:success': 'showSuccessMessage',
'show:error': 'showErrorMessage'
},
radioEvents: {
'login:user': 'showProfileButton',
'logout:user': 'hideProfileButton'
},
showSuccessMessage(message) {
// ...
},
showErrorMessage(message) {
// ...
},
showProfileButton(user) {
// ...
},
hideProfileButton(user) {
// ...
}
});
```
In an unrelated module:
```javascript
import Radio from 'backbone.radio';
import User from './models/user';
const notifyChannel = Radio.channel('notify');
const userModel = new User();
// The following will call Notification.showErrorMessage(message)
notifyChannel.request('show:error', 'A generic error occurred!');
// The following will call Notification.showProfileButton(user)
notifyChannel.trigger('login:user', userModel);
```
[Live example](https://jsfiddle.net/marionettejs/dv40a0t2/)
---
## File: docs/basics.md
# Common Marionette Concepts
This document covers the basic usage patterns and concepts across Marionette.
This includes things like calling conventions, setting attributes, common option
patterns etc.
## Documentation Index
* [Using ES6 Modules](#using-es6-modules)
* [Class-based Inheritance](#class-based-inheritance)
* [Value Attributes](#value-attributes)
* [Functions Returning Values](#functions-returning-values)
* [Binding Attributes on Instantiation](#binding-attributes-on-instantiation)
* [Common Marionette Functionality](./common.md)
## Using ES6 Modules
Marionette still supports using the library via an inline script.
The UMD build supports `noConflict()`.
```html
```
The recommended solution is to choose a solution like a [package manager](./installation.md)
to allow for ES6 module importing of the library. The best way to import is using name imports.
```javascript
import { View } from 'backbone.marionette';
import * as Mn from 'backbone.marionette';
new View({ el: 'body' });
new Mn.Application();
```
However to support backwards compatibility Marionette exports all of its classes and
functions on a default object. This default export may be removed in a future version of
Marionette and it is recommend to migrate to a named imports.
```javascript
import Marionette from 'backbone.marionette';
new Marionette.Application();
```
## Class-based Inheritance
Like [Backbone](http://backbonejs.org/#Model-extend), Marionette utilizes the
[`_.extend`](http://underscorejs.org/#extend) function to simulate class-based
inheritance. [All built-in classes](./classes.md), such as `Marionette.View`, `Marionette.MnObject`
and everything that extend these provide an `extend` method for just this purpose.
In the example below, we create a new pseudo-class called `MyView`:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({});
```
You can now create instances of `MyView` with JavaScript's `new` keyword:
```javascript
const view = new MyView();
```
### Value Attributes
When we extend classes, we can provide class attributes with specific values by
defining them in the object we pass as the `extend` parameter:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
className: 'bg-success',
template: '#template-identifier',
regions: {
myRegion: '.my-region'
},
modelEvents: {
change: 'removeBackground'
},
removeBackground() {
this.$el.removeClass('bg-success');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/k93pejyb/)
When we instantiate `MyView`, each instance will be given a `.bg-success` class
with a `myRegion` region created on the `.my-region` element.
### Functions Returning Values
In almost every instance where we can set a value, we can also assign a function
to figure out the value at runtime. In this case, Marionette will run the
function on instantiation and use the returned value:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
className() {
return this.model.successful() ? 'bg-success' : 'bg-error';
},
template: '#template-identifier',
regions() {
return {
myRegion: '.my-region'
};
},
modelEvents() {
const wasSuccessful = this.model.successful();
return {
change: wasSuccessful ? 'removeBackground' : 'alert'
};
},
removeBackground() {
this.$el.removeClass('bg-success');
},
alert() {
console.log('model changed');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/nn1754fc/)
As we can see, almost all of the attributes here can be worked out dynamically.
In most cases, Marionette will call the function once at instantiation, or first
render, and preserve the value throughout the lifetime of the View. There are
some exceptions to this rule - these will be referred to with their respective
documentation.
### Function Context
When using functions to set attributes, Marionette will assign the instance of
your new class as `this`. You can use this feature to ensure you're able to
access your object in cases where `this` isn't what you might expect it to be.
### Binding Attributes on Instantiation
In Marionette, most attributes can be bound on class instantiation in addition
to being set when the [class is defined](#class-based-inheritance). You can use
this to bind events, triggers, models, and collections at runtime:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
template: '#template-identifier'
});
const myView = new MyView({
triggers: {
'click a': 'show:link'
}
});
```
This will set a trigger called `show:link` that will be fired whenever the user
clicks an `` inside the view.
Options set here will override options set on class definition. So, for example:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
template: '#template-identifier',
triggers: {
'click @ui.save': 'save:form'
}
});
const myView = new MyView({
triggers: {
'click a': 'show:link'
}
});
```
In this example, the trigger for `save:form` will no longer be fired, as the
trigger for `show:link` completely overrides it.
## Setting Options
Marionette can set options when you instantiate a class. This lets you override
many class-based attributes when you need to. You can also pass new information
specific to the object in question that it can access through special helper
methods.
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
checkOption() {
console.log(this.getOption('foo'));
}
});
const view = new MyView({
foo: 'some text'
});
view.checkOption(); // prints 'some text'
```
[Live example](https://jsfiddle.net/marionettejs/6n02ex1m/)
## Common Marionette Functionality
Marionette has a few methods and core functionality that are common to [all classes](./classes.md).
[Continue Reading...](./common.md).
---
## File: docs/classes.md
# Marionette Classes
Marionette follows Backbone's [pseudo-class architecture](./basics.md#class-based-inheritance).
This documentation is meant to provide a comprehensive listing of those classes so that
the reader can have a high-level view and understand functional similarities between the classes.
All of these classes share a [common set of functionality](./common.md).
### [Marionette.View](./marionette.view.md)
A `View` is used for managing portions of the DOM via a single parent DOM element or `el`.
It provides a consistent interface for managing the content of the `el` which is typically
administered by serializing a `Backbone.Model` or `Backbone.Collection` and rendering
a template with the serialized data into the `View`s `el`.
The `View` provides event delegation for capturing and handling DOM interactions as well as
the ability to separate concerns into smaller, managed child views.
`View` includes:
- [The DOM API](./dom.api.md)
- [Class Events](./events.class.md#view-events)
- [DOM Interactions](./dom.interactions.md)
- [Child Event Bubbling](./events.md#event-bubbling)
- [Entity Events](./events.entity.md)
- [View Rendering](./view.rendering.md)
- [Prerendered Content](./dom.prerendered.md)
- [View Lifecycle](./view.lifecycle.md)
A `View` can have [`Region`s](#marionetteregion) and [`Behavior`s](#marionettebehavior)
### [Marionette.CollectionView](./marionette.collectionview.md)
A `CollectionView` like `View` manages a portion of the DOM via a single parent DOM element
or `el`. This view manages an ordered set of child views that are shown within the view's `el`.
These children are most often created to match the models of a `Backbone.Collection` though a
`CollectionView` does not require a `collection` and can manage any set of views.
`CollectionView` includes:
- [The DOM API](./dom.api.md)
- [Class Events](./events.class.md#collectionview-events)
- [DOM Interactions](./dom.interactions.md)
- [Child Event Bubbling](./events.md#event-bubbling)
- [Entity Events](./events.entity.md)
- [View Rendering](./view.rendering.md)
- [Prerendered Content](./dom.prerendered.md)
- [View Lifecycle](./view.lifecycle.md)
A `CollectionView` can have [`Behavior`s](#marionettebehavior).
### [Marionette.Region](./marionette.region.md)
Regions provide consistent methods to manage, show and destroy views in your
applications and views.
`Region` includes:
- [Class Events](./events.class.md#region-events)
- [The DOM API](./dom.api.md)
### [Marionette.Behavior](marionette.behavior.md)
A `Behavior` provides a clean separation of concerns to your view logic, allowing you to
share common user-facing operations between your views.
`Behavior` includes:
- [Class Events](./events.class.md#behavior-events)
- [DOM Interactions](./dom.interactions.md)
- [Entity Events](./events.entity.md)
### [Marionette.Application](marionette.application.md)
An `Application` provides hooks for organizing and initiating other elements and a view tree.
`Application` includes:
- [Class Events](./events.class.md#application-events)
- [Radio API](./backbone.radio.md#marionette-integration)
- [MnObject's API](./marionette.mnobject.md)
An `Application` can have a single [region](./marionette.application.md#application-region).
### [Marionette.MnObject](marionette.mnobject.md)
`MnObject` incorporates backbone conventions `initialize`, `cid` and `extend`.
`MnObject` includes:
- [Class Events](./events.class.md#mnobject-events)
- [Radio API](./backbone.radio.md#marionette-integration).
## Routing in Marionette
Users of versions of Marionette prior to v4 will notice that a router is no longer bundled.
The [Marionette.AppRouter](https://github.com/marionettejs/marionette.approuter) was extracted
and the core library will no longer hold an opinion on routing.
[Continue Reading](./routing.md) about routing in Marionette.
---
## File: docs/common.md
# Common Marionette Functionality
Marionette has a few methods that are common to [all classes](./classes.md).
## Documentation Index
* [initialize](#initialize)
* [extend](#extend)
* [Events API](#events-api)
* [triggerMethod](#triggermethod)
* [bindEvents](#bindevents)
* [unbindEvents](#unbindevents)
* [bindRequests](#bindrequests)
* [unbindRequests](#unbindrequests)
* [normalizeMethods](#normalizemethods)
* [getOption](#getoption)
* [mergeOptions](#mergeoptions)
* [The `options` Property](#the-options-property)
### `initialize`
Like the backbone classes, `initialize` is a method you can define on any Marionette class
that will be called when the class is instantiated and will be passed any arguments passed
at instantiation. The first argument may contain [options](#getoption) the class attaches
to the instance.
```js
import { MnObject } from 'backbone.marionette';
const MyObject = MnObject.extend({
initialize(options, arg2) {
console.log(options.foo, this.getOption('foo'), arg2);
}
});
const myObject = new MyObject({ foo: 'bar' }, 'baz'); // logs "bar" "bar" "baz"
```
[Live example](https://jsfiddle.net/marionettejs/1ytrwyog/)
### `extend`
Borrowed from backbone, `extend` is available on all class definitions for
[class based inheritance](./basics.md#class-based-inheritance)
### Events API
The [Backbone.Events API](http://backbonejs.org/#Events) is available to all classes.
Each Marionette class can both `listenTo` any object with this API and have events
triggered on the instance.
**Note** The events API should not be confused with [view `events`](/.dom.interactions.md#view-events)
which capture DOM events.
### `triggerMethod`
Trigger an event and [a corresponding method](./events.md#onevent-binding) on the object.
It is the same as `Backbone`'s [`trigger`](http://backbonejs.org/#Events-trigger)
but with the additional method handler.
When an event is triggered, the first letter of each section of the
event name is capitalized, and the word "on" is prepended to the front
of it. Examples:
* `triggerMethod('foo')` fires the "onFoo" function
* `triggerMethod('before:foo')` fires the "onBeforeFoo" function
All arguments that are passed to the `triggerMethod` call are passed along
to both the event and the method, with the exception of the event name not
being passed to the corresponding method.
`triggerMethod('foo', bar)` will call `onFoo(bar){...})`
```javascript
import { MnObject } from 'backbone.marionette';
const MyObject = MnObject.extend({
initialize(){
this.triggerMethod('foo', 'baz');
},
onFoo(bar){
console.log(bar);
}
});
const myObj = new MyObject(); // console.log "baz"
myObj.triggerMethod('foo', 'qux'); // console.log "qux"
```
More information on `triggerMethod` can be found in the [Marionette events documentation](./events.md#triggermethod).
### `bindEvents`
This method is used to bind any object that works with the [`Backbone.Events` API](#events-api).
This includes all Backbone classes, Marionette classes and [Radio](./backbone.radio.md) channels.
```javascript
import Radio from 'backbone.radio';
import { View } from 'backbone.marionette';
const MyView = View.extend({
fooEvents: {
'change:foo': 'doSomething'
},
initialize(){
this.fooChannel = Radio.channel('foo');
this.bindEvents(this.fooChannel, this.fooEvents);
},
doSomething(){
// the "change:foo" event was fired from the radio channel
// respond to it appropriately, here.
}
});
```
[Live example](https://jsfiddle.net/marionettejs/L640ecac/)
The first parameter is the `entity` (Backbone.Model, Backbone.Collection or
any object that has Backbone.Events mixed in) to bind the events from.
The second parameter is a hash of `{ 'event:name': 'eventHandler' }`
configuration. A function can be supplied instead of a string handler name.
**Errors** An error will be thrown if the second parameter is not an object.
### `unbindEvents`
This method is used to unbind any object that works with the [`Backbone.Events` API](#events-api).
This includes all Backbone classes, Marionette classes and [Radio](./backbone.radio.md) channels.
Calling this method without a events hash will unbind all events from the channel.
```javascript
import Radio from 'backbone.radio';
import { View } from 'backbone.marionette';
const MyView = View.extend({
fooEvents: {
'change:foo': 'onChangeFoo',
'stop': 'onStop'
},
initialize(){
this.fooChannel = Radio.channel('foo');
this.bindEvents(this.fooChannel, this.fooEvents);
},
onChangeFoo(){
// the "change:foo" event was fired from the radio channel
// respond to it appropriately, here.
// Doing something
this.listenTo(this.fooChannel, 'adhoc', this.render);
},
onStop() {
// Removes all fooEvents
this.unbindEvents(this.fooChannel, this.fooEvents);
// Removes all bound fooChannel events including `adhoc`
this.unbindEvents(this.fooChannel);
}
});
```
The first parameter is the `entity` (Backbone.Model, Backbone.Collection or
any object that has Backbone.Events mixed in) to bind the events from.
The second parameter is a hash of `{ 'event:name': 'eventHandler' }`
configuration. A function can be supplied instead of a string handler name.
If the second parameter is not supplied, all listeners are removed.
[Live example](https://jsfiddle.net/marionettejs/yvsfm65c/)
### `bindRequests`
This method is used to bind any object that works with the [`Backbone.Radio` Request API](https://github.com/marionettejs/backbone.radio#backboneradiorequests).
This includes [Radio](./backbone.radio.md) channels.
```javascript
import Radio from 'backbone.radio';
import { View } from 'backbone.marionette';
const MyView = View.extend({
channelName: 'myChannelName',
radioRequests: {
'foo:bar': 'doFooBar'
},
initialize() {
const channel = Radio.channel(this.channelName);
this.bindRequests(channel, this.radioRequests);
},
doFooBar() {
console.log('foo:bar');
return 'bar';
}
});
const myView = new MyView();
const channel = Radio.channel('myChannelName');
channel.request('foo:bar'); // Logs 'foo:bar' and returns 'bar'
```
[Live example](https://jsfiddle.net/marionettejs/hmjgkg7w/)
The first parameter, `channel`, is an instance from `Radio`.
The second parameter is a hash of `{ 'request:name': 'replyHandler' }`
configuration. A function can be supplied instead of a string handler name.
**Errors** An error will be thrown if the second parameter is not an object.
### `unbindRequests`
This method is used to unbind any object that works with the [`Backbone.Radio` Request API](https://github.com/marionettejs/backbone.radio#backboneradiorequests).
Calling this method without a radio requests hash will unbind all requests
from the channel.
**NOTE: To avoid memory leaks, `unbindRequests` should be called
in or before `onBeforeDestroy`.**
```javascript
import Radio from 'backbone.radio';
import { View } from 'backbone.marionette';
const MyView = View.extend({
channelName: 'myChannelName',
radioRequests: {
'foo:bar': 'doFooBar'
},
onAttach() {
const channel = Radio.channel(this.channelName);
this.bindRequests(channel, this.radioRequests);
},
onBeforeDetach() {
const channel = Radio.channel(this.channelName);
this.unbindRequests(channel, this.radioRequests);
}
});
```
[Live examples](https://jsfiddle.net/marionettejs/r5kmwwke/)
The first parameter, `channel`, is an instance from `Radio`.
The second parameter is a hash of `{ 'request:name': 'replyHandler' }`
configuration. A function can be supplied instead of a string handler name.
If the second parameter is not supplied, all handlers are removed.
### `normalizeMethods`
Receives a hash of event names and functions and/or function names, and returns the
same hash with the function names replaced with the function references themselves.
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
initialize() {
const hash = {
'action:one': 'handleActionOne', // This will become a reference to `this.handleActionOne`
'action:two': this.handleActionTwo
};
this.normalizedHash = this.normalizeMethods(hash);
},
do(action) {
this.normalizedHash[action]();
},
handleActionOne() {
console.log('action:one was fired');
},
handleActionTwo() {
console.log('action:two was fired');
}
});
const myView = new MyView();
myView.do('action:one');
myView.do('action:two');
```
[Live example](https://jsfiddle.net/marionettejs/zzjhm4p1/)
### `getOption`
To access an option, we use the `getOption` method. `getOption` will fall back
to the value of the same name defined on the instance if not defined in the options.
```javascript
import { View } from 'backbone.marionette';
const View = View.extend({
classVal: 'class value',
initialize(){
this.instanceVal = 'instance value'
}
});
const view = new View({ optVal: 'option value' });
view.getOption('instanceVal'); // instance value
view.getOption('classVal'); // class value
view.getOption('optVal'); // option value
const view2 = new View({ instanceVal: 'foo', classVal: 'bar', optVal: 'baz' });
view.getOption('instanceVal'); // foo
view.getOption('classVal'); // bar
view.getOption('optVal'); // baz
```
[Live example](https://jsfiddle.net/marionettejs/ekvb8wwa/)
#### Falsey values
The `getOption` function will return any falsey value from the `options`,
other than `undefined`. If an object's options has an undefined value, it will
attempt to read the value from the object directly.
For example:
```javascript
import { MnObject } from 'backbone.marionette';
const MyObject = MnObject.extend({
foo: 'bar',
initialize() {
console.log(this.getOption('foo'));
}
});
const model1 = new MyObject(); // => "bar"
const myObj = {};
console.log(myObj.foo); // undefined
const model2 = new MyObject({ foo: myObj.foo }); // => "bar"
```
[Live example](https://jsfiddle.net/marionettejs/2ddk28ap/)
In this example, "bar" is returned both times because the second
example has an undefined value for `f`.
### `mergeOptions`
The `mergeOptions` method takes two arguments: an `options` object and `keys` to
pull from the options object. Any matching `keys` will be merged onto the
class instance. For example:
```javascript
import { MnObject } from 'backbone.marionette';
const MyObject = MnObject.extend({
initialize(options) {
this.mergeOptions(options, ['model', 'something']);
// this.model and this.something will now be available
}
});
const myObject = new MyObject({
model: new Backbone.Model(),
something: 'test',
another: 'value'
});
console.log(myObject.model);
console.log(myObject.something);
console.log(myObject.getOption('another'));
```
[Live example](https://jsfiddle.net/marionettejs/ub510cbx/)
In this example, `model` and `something` are directly available on the
`MyObject` instance, while `another` must be accessed via `getOption`. This is
handy when you want to add extra keys that will be used heavily throughout the
defined class.
### The `options` Property
The Marionette classes accept an `options` property in the class definition
which is merged with the `options` argument passed at instantiation. The
values from the passed in `options` overrides the property values.
> The `options` argument passed in `initialize` method is equal to the passed at
> class instantiation. To get the option inside initialize considering the
> `options` property is necessary to use `getOption`
```javascript
import { MnObject } from 'backbone.marionette';
const MyObject = MnObject.extend({
options: {
foo: 'bar',
another: 'thing'
},
initialize(options) {
console.log(options.foo) // undefined
console.log(this.getOption('foo')) // 'bar'
console.log(this.getOption('another')) // 'value'
}
});
const myObject = new MyObject({
another: 'value'
});
```
## Marionette Classes
Marionette provides a few classes for building your view tree and
application structure.
[Continue Reading...](./classes.md).
---
## File: docs/dom.api.md
# The DOM API
With the release of Marionette 3.2, developers can remove the dependency on
jQuery and integrate with the DOM using a custom api.
## API Methods
The DOM API manages the DOM on behalf of [each view class and `Region`](./classes.md).
It defines the methods that actually attach and remove views and children.
[The default API](#the-default-api) depends on Backbone's jQuery `$` object however it does not
rely on jQuery-specific behavior. This should make it easier to develop your own
API. You will, however, [need to also handle Backbone's jQuery integration](#backbone-jquery-integration).
### `createBuffer()`
Returns a new HTML DOM node instance. The resulting node can be passed into the
other DOM functions.
### `getDocumentEl(el)`
Look up the top level element of `el`. Used by Marionette to determine attachment.
```javascript
const elIsAttached = this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);
```
### `getEl(selector)`
Lookup the `selector` string withing the DOM. The `selector` may also be a DOM element.
It should return an array-like object of the node.
### `findEl(el, selector)`
Lookup the `selector` string within the DOM node `el`. It should return an array-like object of nodes.
### `hasEl(el, childEl)`
Returns true if the el contains the node childEl
### `detachEl(el)`
Detach `el` from the DOM without removing listeners.
### `replaceEl(newEl, oldEl)`
Remove `oldEl` from the DOM and put `newEl` in its place.
### `swapEl(el1, el2)`
Swaps the location of `el1` and `el2` in the DOM.
Both els must have a parentNode to be able to swap.
### `setContents(el, html)`
Replace the contents of `el` with the HTML string of `html`. Unlike other DOM
functions, this only takes a literal string for its second argument.
### `appendContents(el, contents)`
Takes the DOM node `el` and appends the DOM node `contents` to the end of the
element's contents.
### `hasContents(el)`
Returns a boolean indicating if the `el` has child nodes.
### `detachContents(el)`
Remove the inner contents of `el` from the DOM while leaving `el` itself in the
DOM.
## The default API
The API used by Marionette by default is attached as `Marionette.DomApi`.
This is useful if you [change the API](#providing-your-own-dom-api) globally,
but want to reuse the default in certain cases.
```javascript
import { setDomApi, DomApi } from 'backbone.marionette';
import MyDOMApi from './mydom';
setDomApi(MyDOMApi);
// Use MyDOMApi everywhere but `Marionette.View`
View.setDomApi(DomApi);
```
## Providing Your Own DOM API
To implement your own DOM API use `setDomApi`:
```javascript
import { setDomApi } from 'backbone.marionette';
import MyDOMApi from './mydom';
setDomApi(MyDOMApi);
```
You can also implement a different DOM API for a particular class:
```javascript
import { View } from 'backbone.marionette';
View.setDomApi(MyDOMApi);
```
`CollectionView`, `Region`, and `View`
all have `setDomApi`. Each extended class may have their own DOM API.
Additionally a DOM API can be partially set:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend();
MyView.setDomApi({
setContents(el, html) {
el.innerHTML = html;
}
});
```
### Backbone jQuery Integration
Backbone.js is tied to jQuery's API for managing DOM manipulation. If you want
to completely remove jQuery from your Marionette app, you'll also have to
provide your own versions of the following methods:
* [`_setAttributes`](http://backbonejs.org/docs/backbone.html#section-170)
* [`delegate`](http://backbonejs.org/docs/backbone.html#section-165)
* [`undelegate`](http://backbonejs.org/docs/backbone.html#section-167)
#### See Also
The DOM API takes care of the other DOM manipulation methods for you. The
[Backbone Wiki](https://github.com/jashkenas/backbone/wiki/using-backbone-without-jquery)
has a good reference for removing jQuery from the app, including Browserify and
Webpack configuration hooks.
---
## File: docs/dom.interactions.md
# DOM Interactions
In addition to what Backbone provides the views, Marionette has additional API
for DOM interactions available to all Marionette [view classes](./classes.md).
### DOM Interactions in a Backbone.View
Marionette's Views extend [`Backbone.View`](http://backbonejs.org/#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.
### Binding To User Input
Views can bind custom events whenever users perform some interaction with the
DOM. Using the view [`events`](#view-events) and [`triggers`](#view-triggers)
handlers lets us either bind user input directly to an action or fire a generic
trigger that may or may not be handled.
#### Event and Trigger Mapping
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:
```javascript
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:
```javascript
' [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](#organizing-your-view).
#### View `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:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
events: {
'click a': 'onShowModal'
},
onShowModal(event) {
console.log('Show the modal');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/jfxwtmxj/)
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:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
events: {
'click a'(event) {
console.log('Show the modal');
}
}
});
```
[Live example](https://jsfiddle.net/marionettejs/obt5vt09/)
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 descendants.
So if you attach a child with the same selector as the parent event handler, the
parent will handle the event for both views.
#### View `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](./events.md). This section will just
cover how to bind these events to views.
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
triggers: {
'click a': 'click:link'
},
onClickLink(view, event) {
console.log('Show the modal');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/exu2s3tL/)
When the `a` tag is clicked here, the `link:click` event is fired. This event
can be listened to using the [`onEvent` Binding](./events.md#onevent-binding)
technique discussed in the [events documentation](./events.md).
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](./events.md#event-bubbling)..
#### View `triggers` Event Object
Event 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`](./features.md#triggerspreventdefault)
and [`stopPropagation`](./features.md#triggersstoppropagating) 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`.
```js
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`](./features.md#triggerspreventdefault), and `stopPropagation`
can be changed with the feature flag [`triggersStopPropagation`](./features.md#triggersstoppropagating).
## Organizing Your View
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:
1. Provide a single defined reference to commonly used UI elements
2. Cache the jQuery selector
3. Query from only the view's template and not the children
### Defining `ui`
To define your `ui` hash, just set an object of named jQuery selectors to the
`ui` attribute of your View:
```javascript
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`.
### Accessing UI Elements
To get the handles to your UI elements, use the `getUI(ui)` method:
```javascript
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');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/rpa58v0g/)
As `$saveButton` here is a jQuery selector, you can call any jQuery methods on
it, according to the jQuery documentation.
#### Referencing UI in `events` and `triggers`
The UI attribute is especially useful when setting handlers in the
[`events`](#view-events) and [`triggers`](#view-triggers) objects - simply use
the `@ui.` prefix:
```javascript
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();
}
});
```
[Live example](https://jsfiddle.net/marionettejs/f2k0wu05/)
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.
---
## File: docs/dom.prerendered.md
# Prerendered Content
[View classes](./classes.md) can be initialized with pre-rendered DOM.
This can be HTML that's currently in the DOM:
```javascript
import { View } from 'backbone.marionette';
const myView = new View({ el: $('#foo-selector') });
myView.isRendered(); // true if '#foo-selector` exists and has content
myView.isAttached(); // true if '#foo-selector` is in the DOM
```
Or it can be DOM created in memory:
```javascript
import { View } from 'backbone.marionette';
const $inMemoryHtml = $('Hello World!');
const myView = new View({ el: $inMemoryHtml });
```
[Live example](https://jsfiddle.net/marionettejs/b2yz38gj/)
In both of the cases at instantiation the view will determine
[its state](./view.lifecycle.md) as to whether the el is rendered
or attached.
**Note** `render` and `attach` events will not fire for the initial
state as the state is set already at instantiation and is not changing.
## Managing `View` children
With [`View`](./marionette.view.md) in most cases the [`render` event](./events.class.md#render-and-beforerender-events)
is the best place to show child views [for best performance](./marionette.view.md#efficient-nested-view-structures).
However with pre-rendered DOM you may need to show child views in `initialize`
as the view will already be rendered.
```javascript
import { View } from 'backbone.marionette';
import HeaderView from './header-view';
const MyBaseLayout = View.extend({
regions: {
header: '#header-region',
content: '#content-region'
},
el: $('#base-layout'),
initialize() {
this.showChildView('header', new HeaderView());
}
});
```
### Managing a Pre-existing View Tree.
It may be the case that you need child views of already existing DOM as well.
To set this up you'll need to query for `el`s down the tree:
```javascript
import { View } from 'backbone.marionette';
import HeaderView from './header-view';
const MyBaseLayout = View.extend({
regions: {
header: '#header-region',
content: '#content-region'
},
el: $('#base-layout'),
initialize() {
this.showChildView('header', new HeaderView({
el: this.getRegion('header').$el.contents()
}));
}
});
```
The same can be done with [`CollectionView`](./marionette.collectionview.md):
```javascript
import { CollectionView } from 'backbone.marionette';
import ItemView from './item-view';
const MyList = CollectionView.extend({
el: $('#base-table'),
childView: ItemView,
childViewContainer: 'tbody',
buildChildView(model, ChildView) {
const index = this.collection.indexOf(model);
const childEl = this.$('tbody').contents()[index];
return new ChildView({
model,
el: childEl
});
}
});
const myList = new MyList({ collection: someCollection });
// Unlike `View`, `CollectionView` should be rendered to build the `children`
myList.render();
```
https://github.com/marionettejs/backbone.marionette/issues/3128
## Re-rendering children of a view with preexisting DOM.
You may be instantiating a `View` with existing HTML, but if you re-render the view,
like any other view, your view will render the `template` into the view's `el` and
any children will need to be re-shown.
So your view will need to be prepared to handle both scenarios.
```javascript
import _ from 'underscore';
import { View } from 'backbone.marionette';
import HeaderView from './header-view';
const MyBaseLayout = View.extend({
regions: {
header: '#header-region',
content: '#content-region'
},
el: $('#base-layout'),
initialize() {
this.showChildView('header', new HeaderView({
el: this.getRegion('header').$el.contents()
}));
},
template: _.template(''),
onRender() {
this.showChildView('header', new HeaderView());
}
});
```
---
## File: docs/events.class.md
# Class Events
Marionette uses [`triggerMethod`](./events.md#triggermethod) internally to trigger various
events used within the [classes](./classes.md). This provides ['onEvent' binding](./events.md#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.
## Documentation Index
* [Application Events](#application-events)
* [`before:start` event](#before-start-event)
* [`start` event](#start-event)
* [Behavior Events](#behavior-events)
* [`initialize` event](#initialize-event)
* [Proxied Events](#proxied-events)
* [Region Events](#region-events)
* [`show` and `before:show` events](#show-and-beforeshow-events)
* [`empty` and `before:empty` events](#empty-and-beforeempty-events)
* [MnObject Events](#mnobject-events)
* [View Events](#view-events)
* [`add:region` and `before:add:region` events](#addregion-and-beforeaddregion-events)
* [`remove:region` and `before:remove:region` events](#removeregion-and-beforeremoveregion-events)
* [CollectionView Events](#collectionview-events)
* [`add:child` and `before:add:child` events](#addchild-and-beforeaddchild-events)
* [`remove:child` and `before:remove:child` events](#removechild-and-beforeremovechild-events)
* [`sort` and `before:sort` events](#sort-and-beforesort-events)
* [`filter` and `before:filter` events](#filter-and-beforefilter-events)
* [`render:children` and `before:render:children` events](#renderchildren-and-beforerenderchildren-events)
* [`destroy:children` and `before:destroy:children` events](#destroychildren-and-beforedestroychildren-events)
* [CollectionView EmptyView Region Events](#collectionview-emptyview-region-events)
* [DOM Change Events](#dom-change-events)
* [`render` and `before:render` events](#render-and-beforerender-events)
* [`attach` and `before:attach` events](#attach-and-beforeattach-events)
* [`detach` and `before:detach` events](#detach-and-beforedetach-events)
* [`dom:refresh` event](#domrefresh-event)
* [`dom:remove` event](#domremove-event)
* [Advanced Event Settings](#advanced-event-settings)
* [Destroy Events](#destroy-events)
* [`destroy` and `before:destroy` events](#destroy-and-beforedestroy-events)
* [Supporting Backbone Views](#supporting-backbone-views)
* [`Marionette.Events` and `triggerMethod`](#marionetteevents-and-triggermethod)
* [Lifecycle Events](#lifecycle-events)
## Application Events
The `Application` object will fire two events:
### `before:start` event
Fired 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` event
Fired as part of the application startup. This is where you should be showing
your views and starting `Backbone.history`.
```javascript
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 } });
```
[Live example](https://jsfiddle.net/marionettejs/ny59rs7b/)
As shown the `options` object is passed into the `Application` as the
second argument to `start`.
#### Application `destroy` events
The `Application` class also triggers [Destroy Events](#destroy-and-beforedestroy-events).
## Behavior Events
### `initialize` event
After the view and behavior are [constructed and initialized](./marionette.behavior.md#events--initialize-order),
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.
```javascript
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.
### Proxied Events
A `Behavior`'s view events [are proxied directly on the behavior](./marionette.behavior.md#proxy-handlers).
**Note** In order to prevent conflict `Behavior` does not trigger [destroy events](#destroy-and-beforedestroy-events)
with its own destruction. A `destroy` event occurring on the `Behavior` will have originated from the related view.
## Region Events
When you show a view inside a region - either using [`region.show(view)`](./marionette.region.md#showing-a-view) or
[`showChildView('region', view)`](./marionette.view.md#showing-a-view) - the `Region` will emit events around the view
events that you can hook into.
The `Region` class also triggers [Destroy Events](#destroy-and-beforedestroy-events).
### `show` and `before:show` events
These 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`.
```javascript
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` events
These 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.
```javascript
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();
```
## MnObject Events
The `MnObject` class triggers [Destroy Events](#destroy-and-beforedestroy-events).
## View Events
### `add:region` and `before:add:region` events
These 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 instantiated for both events.
### `remove:region` and `before:remove:region` events
These 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
## CollectionView Events
The `CollectionView` triggers unique events specifically related to child management.
### `add:child` and `before:add:child` events
These events fire before (`before:add:child`) and after (`add:child`) each child view
is instantiated and added to the [`children`](./collectionview.md#collectionviews-children).
These will fire once for each item in the attached collection or for any view added using
[`addChildView`](./collectionview.md#adding-a-child-view).
### `remove:child` and `before:remove:child` events
These events fire before (`before:remove:child`) and after (`remove:child`) each child view
is removed to the [`children`](./collectionview.md#collectionviews-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`](./collectionview.md#removing-a-child-view).
**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`](#destroychildren-and-beforedestroychildren-events).
### `sort` and `before:sort` events
These events fire before (`before:sort`) and after (`sort`) sorting the children in the `CollectionView`.
These events will only fire if there are [`children`](./collectionview.md#collectionviews-children)
and a [`viewComparator`](./collectionview.md#defining-the-viewcomparator)
### `filter` and `before:filter` events
These events fire before (`before:filter`) and after (`filter`) filtering the children in the `CollectionView`.
This event will only fire if there are [`children`](./collectionview.md#collectionviews-children)
and a [`viewFilter`](./collectionview.md#defining-the-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.
```javascript
const MyCollectionView = CollectionView.extend({
onBeforeFilter(myCollectionView) {
console.log('Nothing has changed yet!');
},
onFilter(myCollectionView, attachedViews, detachedViews) {
console.log('Array of attached views', attachedViews);
console.log('Array of detached views', detachedViews);
}
});
```
### `render:children` and `before:render:children` events
Similar to [`Region` `show` and `before:show` events](#show-and-beforeshow-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`](./marionette.collectionview.md#collectionviews-children)
### `destroy:children` and `before:destroy:children` events
These 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`](./collectionview.md#collectionviews-children).
### CollectionView EmptyView Region Events
The `CollectionView` uses a region internally that can be used to know when the empty view is show or destroyed.
See [Region Events](#region-events).
```javascript
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();
```
## DOM Change Events
### `render` and `before:render` events
Reflects 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.
```javascript
import { View, CollectionView } from 'backbone.marionette';
import MyChildView from './MyChildView';
const MyView = View.extend({
template: _.template(''),
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](./dom.prerendered.md)
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` events
Reflects 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` events
Reflects 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` event
Reflects when the _contents_ of a view's `el` change in the DOM.
This event will fire when the view is first [`attach`ed](#attach-and-beforeattach-events).
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` event
Reflects 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](#detach-and-beforedetach-events).
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.
### Advanced Event Settings
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.
```javascript
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 Events
### `destroy` and `before:destroy` events
Every 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`](#domremove-event) or [`before:detach`] for DOM related clean up.
```javascript
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` events
Similar to `destroy`, `CollectionView` has events for when all of its children
are destroyed. See [the CollectionView's events](#destroychildren-and-beforedestroychildren-events)
for more information.
## Supporting Backbone Views
### `Marionette.Events` and `triggerMethod`
Internally Marionette uses [`triggerMethod`](./common.md#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:
```javascript
import { Events } from 'backbone.marionette';
const MyBbView = Backbone.View.extend(Events);
```
or for all `Backbone.View`s
```javascript
_.extend(Backbone.View.prototype, Events);
```
### Lifecycle 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.
```javascript
// 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');
}
});
```
#### DOM Change Lifecycle Events
As mentioned in [Advanced Event Settings](#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](#dom-change-events) other than render.
You can add the view events monitor to any non-Marionette view:
```javascript
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
}
});
```
---
## File: docs/events.entity.md
# Entity events
The [`View`, `CollectionView` and `Behavior`](./classes.md) can bind to events that occur on attached models and
collections - this includes both [standard backbone-events](http://backbonejs.org/#Events-catalog) and custom events.
Event handlers are called with the same arguments as if listening to the entity directly
and called with the context of the view instance.
### Model Events
For example, to listen to a model's events:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
modelEvents: {
'change:attribute': 'onChangeAttribute'
},
onChangeAttribute(model, value) {
console.log('New value: ' + value);
}
});
```
[Live example](https://jsfiddle.net/marionettejs/auvk4hps/)
The `modelEvents` attribute passes through all the arguments that are passed
to `model.trigger('event', arguments)`.
The `modelEvents` attribute can also take a
[function returning an object](basics.md#functions-returning-values).
#### Function Callback
You can also bind a function callback directly in the `modelEvents` attribute:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
modelEvents: {
'change:attribute'() {
console.log('attribute was changed');
}
}
});
```
[Live example](https://jsfiddle.net/marionettejs/zaxLe6au/)
### Collection Events
Collection events work exactly the same way as [`modelEvents`](#model-events)
with their own `collectionEvents` key:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
collectionEvents: {
sync: 'onSync'
},
onSync(collection) {
console.log('Collection was synchronised with the server');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/7qyfeh9r/)
The `collectionEvents` attribute can also take a
[function returning an object](basics.md#functions-returning-values).
Just as in `modelEvents`, you can bind function callbacks directly inside the
`collectionEvents` object:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
collectionEvents: {
'update'() {
console.log('the collection was updated');
}
}
});
```
[Live example](https://jsfiddle.net/marionettejs/ze8po0x5/)
### Listening to Both
If your view has a `model` and `collection` attached, it will listen for events
on both:
```javascript
import { View } from 'backbone.marionette';
const MyView = View.extend({
modelEvents: {
'change:someattribute': 'onChangeSomeattribute'
},
collectionEvents: {
'update': 'onCollectionUpdate'
},
onChangeSomeattribute() {
console.log('someattribute was changed');
},
onCollectionUpdate() {
console.log('models were added or removed in the collection');
}
});
```
[Live example](https://jsfiddle.net/marionettejs/h9ub5hp3/)
In this case, Marionette will bind event handlers to both.