<!-- Documentation snapshot: package 5.0.0-beta.1; channel next; base revision b06750c507494441f0b2298766b70087e45346a2; local changes false; original source SHA-256 ecc54967f0964ae721d16a769db30016986a252eb391da5f3380f7d3b6b5adc3. -->

# Marionette Events

Marionette provides its own `Events` primitive for communication between
objects. It is exported from `marionette`, mixed into every
[Marionette class](/docs/classes.md), and does not require Backbone. These object
events are separate from [DOM events](/docs/dom-interactions.md#canonical-view-interaction).

## Documentation Index

* [Triggering and Listening to Events](#triggering-and-listening-to-events)
  * [Events API](#events-api)
  * [`triggerMethod`](#triggermethod)
  * [Listening to Events](#listening-to-events)
    * [`onEvent` Binding](#onevent-binding)
  * [Backbone interop](#backbone-interop)
  * [Private bookkeeping](#private-bookkeeping)
  * [View events and triggers](#view-events-and-triggers)
  * [View entity events](#view-entity-events)
* [Child View Events](#child-view-events)
  * [Event Bubbling](#event-bubbling)
    * [Using CollectionView](#using-collectionview)
  * [A Child View's Event Prefix](#a-child-views-event-prefix)
  * [Explicit Event Listeners](#explicit-event-listeners)
    * [Attaching Functions](#attaching-functions)
    * [Using `CollectionView`'s `childViewEvents`](#using-collectionviews-childviewevents)
  * [Triggering Events on Child Events](#triggering-events-on-child-events)
    * [Using `CollectionView`'s `childViewTriggers`](#using-collectionviews-childviewtriggers)
* [Lifecycle Events](#lifecycle-events)

## Triggering and Listening to Events

Use the `Events` export directly when a plain object needs Marionette's event
API, or use the same methods already present on a Marionette class.

```javascript
import { Events, MnObject } from 'marionette';

const emitter = Object.assign({}, Events);
const listener = new MnObject();

listener.listenTo(emitter, 'status:changed', status => {
  console.log(status);
});

emitter.trigger('status:changed', 'ready');
listener.stopListening(emitter);
```

### Events API

| Method | Purpose |
| --- | --- |
| `on(name, callback, context?)` | Register a callback on this object. |
| `off(name?, callback?, context?)` | Remove matching callbacks registered with `on`. |
| `trigger(name, ...args)` | Trigger one or more named events. |
| `once(name, callback, context?)` | Register a callback that is removed after its first call. |
| `listenTo(object, name, callback)` | Listen to another emitter while tracking the relationship on this object. |
| `stopListening(object?, name?, callback?)` | Remove relationships created with `listenTo` or `listenToOnce`. |
| `listenToOnce(object, name, callback)` | Listen to another emitter once. |
| `triggerMethod(name, ...args)` | Trigger an event and call its matching `onEventName` method. |

`trigger`, `on`, `off`, `once`, `listenTo`, `listenToOnce`, and
`stopListening` accept space-separated event names. `triggerMethod` delegates
to `trigger` for listener notification, but call it once per event when you
need matching `onEventName` methods. Object-form `trigger` maps each key to the
single value passed to that event's handlers:

```javascript
emitter.on('start stop', value => console.log(value));
emitter.trigger('start stop', 'manual');

emitter.trigger({
  start: 'automatic',
  stop: 'complete'
});
```

During a multi-name or mapped `trigger` call, calling `off()` from a handler
removes subscriptions for subsequent calls but does not cancel the remaining
event names in the current call. For example, `off()` inside a `start` handler
still allows the existing `stop` handlers in `trigger('start stop')` to run.
Calling `off('stop', handler)` inside `start` instead removes that handler before
`stop` is dispatched. A nested `trigger` call uses the current subscriptions.

`once` registers its generated callback through the object's overridable
`on` method, and `listenToOnce` registers through overridable `listenTo`.
This preserves the extension points used by event-lifecycle mixins. Likewise,
`listenTo` and `stopListening` call an emitter's documented three-argument
`on` and `off` methods exactly once per binding.

### `triggerMethod`

`triggerMethod` invokes the matching `onEventName` method when it exists, then
fires the named event on the instance. If there are no listeners or
matching method, the call still succeeds. All arguments after the event name
are passed to both the method and event handlers.

```javascript
import { View } from 'marionette';

const MyView = View.extend({
  callMethod(myString) {
    console.log(myString + ' was passed');
  }
});

const myView = new MyView();
myView.on('something:happened', myView.callMethod);

/* Calls callMethod('foo'); */
myView.triggerMethod('something:happened', 'foo');
```

**The `triggerMethod` method is available to [all Marionette classes](/docs/common.md#triggermethod).**

### Listening to Events

Use `on` to register a callback directly on an emitter:

```javascript
import { View } from 'marionette';

const MyView = View.extend({
  initialize() {
    this.on('event:happened', this.logCall);
  },

  logCall(myVal) {
    console.log(myVal);
  }
});
```

Use `listenTo` when the listener should own and later clean up the subscription:

```javascript
import { View } from 'marionette';

const OtherView = View.extend({
  initialize({ source }) {
    this.listenTo(source, 'event:happened', this.logCall);
  },

  logCall(myVal) {
    console.log(myVal);
  }
});

const MyView = View.extend();

const myView = new MyView();

const otherView = new OtherView({ source: myView });

myView.triggerMethod('event:happened', 'someValue'); // Logs 'someValue'
```

`listenTo` calls the callback with the listener as its context and records the
relationship for `stopListening`. A direct `on` subscription must be removed
with `off` when it is no longer needed. Marionette view lifecycles also clean up
their tracked `listenTo` relationships during destruction.

### Backbone interop

Backbone models and collections are observable event sources. Marionette
`listenTo` and `stopListening` work directly with their native event interface,
without changing Backbone. Select the integration separately when a View needs
Backbone model reads, serialization, or structural collection observation:

```javascript
import BackboneApi from '@mnjs/adapters/backbone';
import Backbone from 'backbone';
import { setDataApi, View } from 'marionette';

setDataApi(BackboneApi);

const model = new Backbone.Model();
const view = new View({ model });

view.listenTo(model, 'change', () => {
  // ...
});
```

The integration subscribes through Backbone's native event methods. It does not
modify Backbone objects or prototypes, so existing listeners and Backbone's
own listener bookkeeping remain intact. Marionette `listenTo` and
`stopListening` interoperate with native Backbone objects, and Backbone can
likewise listen to Marionette evented objects.

### Event names

Event callbacks are dispatched only when they were explicitly registered with
`on`, `once`, `listenTo`, or `listenToOnce`. Names that also exist on
`Object.prototype`, including `constructor`, `toString`, and `__proto__`, are
ordinary event names and do not affect the event store's prototype. Remove them
through the corresponding `off` or `stopListening` API as with any other name.

### Private bookkeeping

Marionette stores event internals under `_rdEvents`, `_rdListeningTo`,
`_rdListeners`, and `_rdListenId`. These fields are private and replace the
Backbone-shaped `_events`, `_listeningTo`, and `_listenId` names. Plugins should
use `on`, `off`, `listenTo`, and `stopListening` instead of reading or writing
either set of private fields.

#### `onEvent` Binding

In addition to triggering listeners, `triggerMethod` can call specially named
methods on the instance. For
example, a view that has been rendered will internally fire `view.triggerMethod('render')`
and call `onRender` - providing a handy way to add behavior to your views.

Determining what method an event will call is easy, we will outline this with an
example using `before:dom:refresh` though this also works with any custom events
you want to fire:

1. Split the words around the `:` characters - so `before`, `dom`, `refresh`
2. Capitalize the first letter of each word - `Before`, `Dom`, `Refresh`
3. Add a leading `on` - `on`, `Before`, `Dom`, `Refresh`
4. Mash it into a single call - `onBeforeDomRefresh`

Using this process, `before:dom:refresh` will call the `onBeforeDomRefresh`
method. Let's see it in action with a custom event:

```javascript
import { View } from 'marionette';

const MyView = View.extend({
  onMyEvent(myVal) {
    console.log(myVal);
  }
});

const myView = new MyView();

myView.triggerMethod('my:event', 'someValue'); // Logs 'someValue'
```

As before, all arguments passed into `triggerMethod` after the event name will make
their way into the event handler. `triggerMethod` does not establish or clean up subscriptions;
use `listenTo` and owner teardown, or explicit `off`, for listener cleanup.

### View `events` and `triggers`

Views can automatically bind DOM events to methods and View events with [`events`](/docs/dom-interactions.md#view-events)
and [`triggers`](/docs/dom-interactions.md#view-triggers) respectively:

```javascript
import { View } from 'marionette';

const MyView = View.extend({
  events: {
    'click a': 'showModal'
  },

  triggers: {
    'keyup input': 'data:entered'
  },

  showModal(event) {
    console.log('Show the modal');
  },

  onDataEntered(view, event) {
    console.log('Data was entered');
  }
});
```

For more information, see the [DOM interactions documentation](/docs/dom-interactions.md#canonical-view-interaction).

### View entity events

Views can automatically bind to its model or collection with [`modelEvents`](/docs/entity-events.md)
and [`collectionEvents`](/docs/entity-events.md) respectively.

```javascript
import { View } from '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');
  }
});
```

For more information, see the [Entity events documentation](/docs/entity-events.md).

## Child View Events

The [`View`](/docs/view.md) and [`CollectionView`](/docs/collection-view.md)
can handle events from their direct managed children through `childViewEvents`,
forward selected names through `childViewTriggers`, or opt into a prefix through
`childViewEventPrefix`. Without one of those configurations, a parent does not
automatically forward every child event. For example:

```javascript
import { View, CollectionView } from 'marionette';

const ChildView = View.extend({
  tagName: 'li',
  template: () => '<a href="#details">Select</a>',

  triggers: {
    'click a': 'select:model'
  }
});

const ListView = CollectionView.extend({
  tagName: 'ul',
  childView: ChildView,

  childViewEvents: {
    'select:model': 'modelSelected'
  },

  modelSelected(childView) {
    console.log('model selected: ' + childView.model.id);
  }
});

const list = new ListView({ collection: [{ id: 'example' }] }).render();
list.el.querySelector('a').click(); // Logs 'model selected: example'
```

### Event Bubbling

Set `childViewEventPrefix: 'childview'` on a parent to forward every child
event as `childview:<eventName>`. The default is `false`, so prefixed forwarding
is opt-in. Explicit `childViewEvents` and `childViewTriggers` still work when
the prefix is disabled. Both `trigger` and `triggerMethod` events can be forwarded.
The parent's matching method runs before its event listeners.

Each level must configure the forwarding it needs. Arguments pass through
unchanged: Marionette does not prepend the child instance to arbitrary events.
DOM `triggers` already supply `(view, event)`, while a custom event must explicitly
supply its View when handlers need it.

```javascript
import { View } from 'marionette';

const MyView = View.extend({
  template: false,
  triggers: {
    click: 'click:view'
  },

  doSomething() {
    this.triggerMethod('did:something', this);
  }
});

const ParentView = View.extend({
  template: () => '<div class="foo-hook"></div>',
  childViewEventPrefix: 'childview',
  regions: {
    foo: '.foo-hook'
  },

  onRender() {
    this.showChildView('foo', new MyView());
  },

  onChildviewClickView(childView) {
    console.log('View clicked ' + childView);
  },

  onChildviewDidSomething(childView) {
    console.log('Something was done to ' + childView);
  }
});
```

**NOTE** `triggers` will automatically pass the child view as an argument to the parent view, however `triggerMethod` will not, and so notice that in the above example, the `triggerMethod` explicitly passes the child view.

#### Using `CollectionView`

The same opt-in applies to a `CollectionView` and its `childView`:

```javascript
import { View, CollectionView } from 'marionette';

const MyChild = View.extend({
  template: false,
  triggers: {
    click: 'click:child'
  }
});

const MyList = CollectionView.extend({
  childView: MyChild,
  childViewEventPrefix: 'childview',
  onChildviewClickChild(childView) {
    console.log('Childview ' + childView + ' was clicked');
  }
});
```

### A Child View's Event Prefix

You can customize the event prefix for events that are forwarded
through the view. To do this, set the `childViewEventPrefix`
on the view or collectionview. For more information on the `childViewEventPrefix` see
[Event bubbling](#event-bubbling).

The default value for `childViewEventPrefix` is `false`. It disables prefixed
forwarding, while explicit child event maps remain active.

```javascript
import { CollectionView, View } from 'marionette';

const MyChildView = View.extend({ template: () => 'Child' });
const MyCollectionView = CollectionView.extend({
  childViewEventPrefix: 'some:prefix',
  childView: MyChildView
});
const collectionView = new MyCollectionView({ collection: [{}] });

collectionView.on('some:prefix:render', childView => {
  console.log('Child rendered', childView);
});
collectionView.render();
```

The `childViewEventPrefix` can be provided in the view definition or
in the constructor function call, to get a view instance.

### Explicit Event Listeners

To call specific functions on event triggers, use the `childViewEvents`
attribute to map child events to methods on the parent view. This takes events
fired on child views - _without the `childview:` prefix_ - and calls the
method referenced or attached function.

```javascript
import { View } from 'marionette';

const MyView = View.extend({
  template: false,
  triggers: {
    click: 'view:clicked'
  }
});

const ParentView = View.extend({
  template: () => '<div class="foo-hook"></div>',
  regions: {
    foo: '.foo-hook'
  },

  childViewEvents: {
    'view:clicked': 'displayMessage'
  },

  onRender() {
    this.showChildView('foo', new MyView());
  },

  displayMessage(childView) {
    console.log('Displaying message for ' + childView);
  }
});
```

#### Attaching Functions

The `childViewEvents` attribute can also attach functions directly to be event
handlers:

```javascript
import { View } from 'marionette';

const MyView = View.extend({
  template: false,
  triggers: {
    click: 'view:clicked'
  }
});

const ParentView = View.extend({
  template: () => '<div class="foo-hook"></div>',
  regions: {
    foo: '.foo-hook'
  },

  childViewEvents: {
    'view:clicked'(childView) {
      console.log('Function called for ' + childView);
    }
  },

  onRender() {
    this.showChildView('foo', new MyView());
  }
});
```

#### Using `CollectionView`'s `childViewEvents`

```javascript
import { CollectionView } from 'marionette';

// childViewEvents can be specified as a hash...
const MyCollectionView = CollectionView.extend({
  childViewEvents: {
    // This callback will be called whenever a child is rendered or emits a `render` event
    render() {
      console.log('A child view has been rendered.');
    }
  }
});
```

### Triggering Events on Child Events

A `childViewTriggers` hash or method permits proxying of child view events without manually
setting bindings. Each own map key selects a child event, and its value names the event
to trigger on the parent. Inherited entries are ignored. `childViewEvents` also
normalizes only own enumerable string keys.

`childViewTriggers` is sugar on top of [`childViewEvents`](#explicit-event-listeners) much
in the same way that [view `triggers`](/docs/dom-interactions.md#view-triggers) are sugar for [view `events`](/docs/dom-interactions.md#view-events).

```javascript
import { View, CollectionView } from 'marionette';

// The child view fires a custom event, `show:message`
const ChildView = View.extend({
  template: () => '<button class="button">Message</button><form><button>Submit</button></form>',

  // Events hash defines local event handlers that in turn may call `triggerMethod`.
  events: {
    'click .button': 'onClickButton'
  },

  triggers: {
    'submit form': 'submit:form'
  },

  onClickButton () {
    // Both `trigger` and `triggerMethod` events will be caught by parent.
    this.trigger('show:message', 'foo');
    this.triggerMethod('show:message', 'bar');
  }
});

// The parent forwards the child's event through childViewTriggers.
const ParentView = CollectionView.extend({
  childView: ChildView,

  childViewTriggers: {
    'show:message': 'child:show:message',
    'submit:form': 'child:submit:form'
  },

  onChildShowMessage (message) {
    console.log('A child view fired show:message with ' + message);
  },

  onChildSubmitForm (childView) {
    console.log('A child view fired submit:form');
  }
});

const GrandParentView = View.extend({
  template: () => '<div class="list"></div>',
  regions: {
    list: '.list'
  },

  onRender() {
    this.showChildView('list', new ParentView({
      collection: this.collection
    }));
  },

  childViewEvents: {
    'child:show:message': 'showMessage'
  },

  showMessage(message) {
    console.log('A child sent: ' + message);
  }
});
```

#### Using `CollectionView`'s `childViewTriggers`

```javascript
import { View, CollectionView } from 'marionette';

// The child view fires a custom event, `show:message`
const ChildView = View.extend({
  template: () => '<button class="button">Message</button><form><button>Submit</button></form>',

  // Events hash defines local event handlers that in turn may call `triggerMethod`.
  events: {
    'click .button': 'onClickButton'
  },

  // Triggers hash converts DOM events directly to view events catchable on the parent.
  // Note that `triggers` automatically pass the first argument as the child view.
  triggers: {
    'submit form': 'submit:form'
  },

  onClickButton () {
    // Both `trigger` and `triggerMethod` events will be caught by parent.
    this.trigger('show:message', 'foo');
    this.triggerMethod('show:message', 'bar');
  }
});

// The parent forwards the child's event through childViewTriggers.
const ParentView = CollectionView.extend({

  childView: ChildView,

  childViewTriggers: {
    'show:message': 'child:show:message',
    'submit:form': 'child:submit:form'
  },

  onChildShowMessage (message) {
    console.log('A child view fired show:message with ' + message);
  },

  onChildSubmitForm (childView) {
    console.log('A child view fired submit:form');
  }
});
```

## Lifecycle Events

Marionette Views fire events during their creation and destruction lifecycle.
For more information see the documentation covering the
[`View` Lifecycle](/docs/lifecycle.md).


[Canonical source](/docs/markdown/docs/events.md) · [Source identity](/docs/manifest.json)
