# Marionette 5.0.0-beta.1 documentation bundle
Version: 5.0.0-beta.1
Channel: next
Publication: beta (published on npm)
Source revision: b06750c507494441f0b2298766b70087e45346a2
Local changes: false
Content SHA-256: 3fe8788a771994d9effd124fee94d7444637a27ec974a5b520ccbf43b55bbec9
Read individual documents for focused tasks. Each section below contains the exact published reading Markdown, including its source identity.
---
Document: docs/common.md
Canonical URL: https://marionettejs.com/docs/common/
Markdown URL: https://marionettejs.com/docs/common.md
Reading SHA-256: db7325305bfd423933d588166774c1307172d38f160978df9386ee4984195440
# Common Marionette Functionality
Marionette classes share a small set of lifecycle, event, request, and option
helpers.
## Documentation Index
* [Shared helpers](#shared-helpers)
* [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)
## Shared helpers
The reusable option, binding, and event helpers are also available from
`@mnjs/utils` for components outside Marionette's classes:
```javascript
import { getOption, normalizeMethods } from '@mnjs/utils';
const component = {
options: { label: 'Inbox' },
getOption,
normalizeMethods,
onOpen() {}
};
component.getOption('label'); // 'Inbox'
component.normalizeMethods({ open: 'onOpen' });
```
Install `@mnjs/utils` directly when importing it in an application. Use the
same version as Marionette during prereleases. Core and native data depend on this
package and use the same implementations. Helpers that read `this` can be mixed
into a component or invoked with `.call(component, ...)`.
### `initialize`
`initialize` is a no-op method that you can override on any Marionette class.
It is called when the class is instantiated and receives the constructor
arguments unchanged. The first argument is conventionally an options object.
Use [`getOption`](#getoption) to read that object together with class defaults.
```javascript
import { MnObject } from 'marionette';
const MyObject = MnObject.extend({
initialize(options, secondArgument) {
console.log(options.foo, this.getOption('foo'), secondArgument);
}
});
new MyObject({ foo: 'bar' }, 'baz'); // logs "bar" "bar" "baz"
```
### `extend`
`extend` is available on Marionette class definitions for
[class-based inheritance](/docs/basics.md#class-based-inheritance).
### Events API
Marionette classes include Marionette's owned [Events API](/docs/events.md). Each
class can emit events and listen to other objects that implement the compatible
event interface, including native Backbone emitters. The separate
[`Backbone integration`](/docs/events.md#backbone-interop) selects data reads and
collection observation; the core Events API does not require Backbone.
The Events API should not be confused with [view `events`](/docs/dom-interactions.md#view-events),
which capture DOM events.
### `triggerMethod`
`triggerMethod` calls a matching method and then triggers an event on the
object. The first letter of each event-name segment is capitalized and `on` is
prepended:
* `triggerMethod('foo')` calls `onFoo` and triggers `foo`.
* `triggerMethod('before:foo')` calls `onBeforeFoo` and triggers `before:foo`.
Arguments after the event name are passed to both the method and event. The
matching method is resolved through `getOption`, runs first with the Marionette
object as its context, and supplies the return value of `triggerMethod`. If that
method throws, the event is not triggered.
```javascript
import { MnObject } from 'marionette';
const MyObject = MnObject.extend({
onFoo(value) {
return value.toUpperCase();
}
});
const object = new MyObject();
object.on('foo', value => console.log(value));
object.triggerMethod('foo', 'bar'); // logs "bar" and returns "BAR"
```
See the [Marionette events documentation](/docs/events.md#triggermethod) for the
complete event and method-handler contract.
### `bindEvents`
`bindEvents(entity, bindings)` uses the Marionette object's `listenTo` API to
bind events from another compatible event emitter. The binding map associates
event names with functions or method names on the listening object. The method
returns the listening object.
Marionette classes and [Radio](/docs/radio.md) channels implement the required
event interface. Backbone models, collections, and other Backbone emitters can
participate directly through compatible `on` and `off` methods. Configure the
[`Backbone integration`](/docs/events.md#backbone-interop) separately when a View
also needs Backbone data reads, serialization, or collection observation.
Binding maps follow the declared object contract. An own enumerable `__proto__`
event name is rejected with code `MN0026` before any listener is added. This restriction applies only to entity-event maps;
Marionette's direct Events API supports `__proto__` as an ordinary event name.
### `unbindEvents`
`unbindEvents(entity, bindings)` stops the subscriptions represented by a
binding map. Without a binding map, it stops every subscription that this
Marionette object established to that entity. It does not remove listeners
owned by other objects or direct handlers registered on the entity. The method
returns the listening object.
When selectively unbinding with a map, an own enumerable `__proto__` event name
is rejected with `MarionetteError` code `MN0026` before any listener is removed.
### `bindRequests`
`bindRequests(channel, bindings)` registers replies on a [Radio](/docs/radio.md)
channel. The binding map associates request names with functions or method names
on the Marionette object. Reply methods run with that object as their context,
and `bindRequests` returns the object.
Binding maps follow the declared object contract. String-named handlers must
resolve to callable methods on the receiver.
### `unbindRequests`
`unbindRequests(channel, bindings)` removes the replies represented by a
binding map. Without a binding map, it removes every reply owned by this object
from that channel. Replies owned by other objects remain registered. The method
returns the object.
> **Warning:** Request bindings created manually retain their owner as reply
> context. To avoid memory leaks, call `unbindRequests` in or before
> `onBeforeDestroy`, and whenever a shorter binding lifetime ends.
`MnObject` and `Application` instead support the declarative `channelName`,
`radioEvents`, and `radioRequests` options; those owned bindings are cleaned up
when the owner is destroyed. A `View` using `bindRequests` directly should call
`unbindRequests` as part of its own cleanup.
The following example shows both event and request bindings remaining scoped to
their owner.
```javascript
import { MnObject, Radio } from 'marionette';
const source = new MnObject();
const channel = Radio.channel('common-owner-bindings');
const unrelatedMessages = [];
source.on('status', value => unrelatedMessages.push(value));
channel.reply('status:other', () => 'other');
const Owner = MnObject.extend({
initialize() {
this.messages = [];
this.bindEvents(source, { status: 'onStatus' });
this.bindRequests(channel, { 'status:current': 'getStatus' });
},
onStatus(value) {
this.messages.push(value);
},
getStatus() {
return this.messages[this.messages.length - 1];
}
});
const owner = new Owner();
source.trigger('status', 'ready');
const ownerReply = channel.request('status:current'); // "ready"
owner.unbindEvents(source);
owner.unbindRequests(channel);
source.trigger('status', 'after');
const ownerReplyAfterCleanup = channel.request('status:current'); // undefined
const unrelatedReplyAfterCleanup = channel.request('status:other'); // "other"
export {
Radio,
owner,
ownerReply,
ownerReplyAfterCleanup,
unrelatedMessages,
unrelatedReplyAfterCleanup
};
```
### `normalizeMethods`
`normalizeMethods(bindings)` returns a fresh map with method-name strings
replaced by function references from the Marionette object. Only the map's own
enumerable string keys are normalized; inherited, symbol, and non-enumerable
properties are ignored. A literal own `__proto__` entry remains a handler key
without changing the returned object's prototype.
Every supplied handler must be a function or a string that resolves to a
callable own or inherited method on the binding context. Otherwise Marionette
throws `MarionetteError` with code `MN0019`. This invariant also applies to
event and request binding maps, including their unbind operations, and to model,
collection, Radio, and child-view event bindings.
```javascript
import { View } from 'marionette';
const MyView = View.extend({
initialize() {
this.normalizedActions = this.normalizeMethods({
'action:one': 'handleActionOne',
'action:two': this.handleActionTwo
});
},
handleActionOne() {
console.log('action:one');
},
handleActionTwo() {
console.log('action:two');
}
});
```
### `getOption`
`getOption(name)` first reads the named value from the merged `options` object.
If that value is `undefined`, it falls back to the same property on the
instance or its prototype. Explicit option values such as `null`, `false`, `0`,
and an empty string are returned without falling back. Function values are
returned without being invoked.
### `mergeOptions`
`mergeOptions(options, keys)` copies selected option values directly onto the
class instance. `keys` must be an array when options are present. Only requested
own enumerable string properties with values other than `undefined` are copied; inherited, symbol,
and non-enumerable properties are ignored.
### The `options` Property
A class-level `options` property supplies defaults. Marionette creates a fresh
`this.options` object for each instance by merging those defaults with the
constructor options; constructor values take precedence. The `options` argument
received by `initialize` remains the raw object supplied by the caller, so use
`getOption` when class defaults must be included.
`mergeOptions` is separate: it copies only named values directly onto the
instance for APIs that need instance properties.
```javascript
import { MnObject } from 'marionette';
const service = { name: 'example' };
const Example = MnObject.extend({
enabled: true,
options: {
mode: 'default'
},
initialize(options) {
this.rawMode = options.mode;
this.mergeOptions(options, ['service']);
}
});
const example = new Example({
enabled: false,
service,
extra: 'kept only in this.options'
});
const rawMode = example.rawMode; // undefined
example.getOption('mode'); // "default"
example.getOption('enabled'); // false
example.getOption('extra'); // "kept only in this.options"
console.log(example.service === service); // true
export { example, rawMode, service };
```
## Marionette Classes
Marionette provides classes for building a view tree and application structure.
[Continue Reading...](/docs/classes.md).
[Canonical source](/docs/markdown/docs/common.md) · [Source identity](/docs/manifest.json)
---
Document: docs/events.md
Canonical URL: https://marionettejs.com/docs/events/
Markdown URL: https://marionettejs.com/docs/events.md
Reading SHA-256: c3bd1948bed6caf6ac6e9a4eafa49f02072d3b9ed1980d7b23145c244faea4ac
# 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: () => 'Select',
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:`. 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: () => '',
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: () => '',
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: () => '',
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: () => '',
// 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: () => '',
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: () => '',
// 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)
---
Document: docs/events.class.md
Canonical URL: https://marionettejs.com/docs/class-events/
Markdown URL: https://marionettejs.com/docs/class-events.md
Reading SHA-256: cb7f4384ed8b3aa6446122cbd6924689564d3639ffbab50c753c138c765b26fc
# Class Events
Class events let you respond as a view renders, a Region shows a view, or an
Application starts and stops. Marionette uses
[`triggerMethod`](/docs/events.md#triggermethod) to dispatch these events, so you can
listen to an event or define its matching
[`onEvent` method](/docs/events.md#onevent-binding).
Arguments depend on the event. Use the signatures below rather than assuming
the first argument is the instance that triggered it; for example, a Behavior's
proxied view events receive the host view.
## Documentation Index
* [Application Events](#application-events)
* [`before:start` event](#beforestart-event)
* [`start` event](#start-event)
* [`before:stop` event](#beforestop-event)
* [`stop` event](#stop-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)
* [Wrapping legacy views](#wrapping-legacy-views)
## Application Events
Application events describe its asynchronous lifecycle. Use a readiness method
when completion must wait for work; event-listener return values are not awaited.
### `before:start` event
Receives `(application, options, context)` before startup completes. The matching
`onBeforeStart(application, options, { signal })` method may return a Promise to
delay readiness. Pass the signal to cancellable work and prevent stale results
from committing application side effects.
### `start` event
Receives `(application, options)` after readiness and owned child startup complete.
The matching `onStart(application, options)` method can show the feature's View.
Both are completion notifications; their return values are not awaited.
Use the [Application lifecycle example](/docs/application.md#starting-an-application)
for startup and the [routing guide](/docs/routing.md) to connect an application's
router. Starting a history service is application setup, not a Marionette lifecycle
requirement.
The `options` passed to a lifecycle operation reach its hooks and events.
Readiness hooks and `before:*` events also receive a context whose signal is
aborted when a later operation invalidates that readiness. A transferred stop
phase retains its original options, context, and un-aborted signal. Only a Promise
returned by `onBeforeStart`, `onBeforeStop`, or `onBeforeDestroy` delays its phase.
See [Application lifecycle](/docs/application.md#application-lifecycle)
for operation results, ordering, and cancellation.
### `before:stop` event
Fired just before the application is stopped. A Promise returned by
`onBeforeStop` delays completion of the stop lifecycle.
### `stop` event
Fired after the application has stopped. This event is a completion
notification and its return value is not awaited.
#### Application `destroy` events
The `Application` class also triggers `before:destroy` and `destroy` as part of
its [asynchronous lifecycle](/docs/application.md#application-lifecycle).
`onBeforeDestroy` is awaited and receives `(application, options, context)`;
`onDestroy` is a completion notification and receives `(application, options)`.
## Behavior Events
### `initialize` event
After the view and behavior are [constructed and initialized](/docs/behavior.md#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 '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](/docs/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)`](/docs/region.md#showing-a-view) or
[`showChildView('region', view)`](/docs/view.md#showing-a-child-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 '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: () => 'hello'
});
const regionElement = document.createElement('div');
const myRegion = new MyRegion({ el: regionElement });
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 '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: () => 'hello'
});
const regionElement = document.createElement('div');
const myRegion = new MyRegion({ el: regionElement });
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 is not yet destroyed in the before event, but is destroyed by `remove:region`.
`removeRegion()` and the View's Region cleanup path emit these events. Destroying
a Region directly does not itself emit the owning View's remove-region events.
## 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 added to [`children`](/docs/collection-view.md#accessing-a-child-view).
Both receive `(collectionView, childView)`; the child is already constructed at
`before:add:child`.
These will fire once for each model in the attached collection or for any view added using
[`addChildView`](/docs/collection-view.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 from the [`children`](/docs/collection-view.md#accessing-a-child-view).
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`](/docs/collection-view.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 fire when there are managed children and `getComparator()` returns
an active comparator, including the default comparator for collection order.
See [`viewComparator`](/docs/collection-view.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`](/docs/collection-view.md#accessing-a-child-view)
and a [`viewFilter`](/docs/collection-view.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 receives `(collectionView, passingViews, filteredViews)`.
Passing Views are the selected result; some may already be attached, while new
ones are rendered and attached by the following child-render pass.
```javascript
import { CollectionView } from 'marionette';
const MyCollectionView = CollectionView.extend({
onBeforeFilter(myCollectionView) {
console.log('Nothing has changed yet!');
},
onFilter(myCollectionView, passingViews, filteredViews) {
console.log('Views passing the filter', passingViews);
console.log('Views excluded by the filter', filteredViews);
}
});
```
### `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`.
Both events receive the complete current presented `children` array, including
already-rendered survivors. An empty result still emits both events with an empty
array while the empty-View Region is updated. “Attached” here means inserted into
the CollectionView container; the container itself may be detached from the document.
### `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`](/docs/collection-view.md#accessing-a-child-view).
### CollectionView EmptyView Region Events
The `CollectionView` uses a Region internally to show or destroy its empty View.
See [Region Events](#region-events).
```javascript
import { CollectionView, View } from 'marionette';
const MyEmptyView = View.extend({ template: () => 'No items' });
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
For `View`, these events bracket template rendering. For `CollectionView`,
they bracket the complete child rebuild/render pass, even without a template.
Both receive the instance as their argument.
`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 'marionette';
const MyChildView = View.extend({ template: () => 'Child' });
const MyView = View.extend({
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());
}
})
```
Adopting [prerendered contents](/docs/prerendered-dom.md) does not itself emit these
events. Use `initialize` for initial child setup on that path. `View#render()`
returns without events when `template` is `false`; `CollectionView#render()`
still emits its render events when its template is `false` or absent.
### `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.
The monitor requires both `isAttached()` and `isRendered()` to be true.
Prerendered contents can establish rendered state, and a CollectionView render
establishes it even without a template.
### `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.
The monitor requires both `isAttached()` and `isRendered()` to be true.
Prerendered contents can establish rendered state, and a CollectionView render
establishes it even without a template.
### 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 Marionette View is constructed.
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 '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`, each class triggers a `before:destroy` and a
`destroy` event. Application uses the separate asynchronous lifecycle described
under [Application Events](#application-events); this section describes the
synchronous owner classes.
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.
For classes with these lifecycle events, once destruction begins, reentrant
`destroy()` calls from `before:destroy` or `destroy`, and later repeated calls,
return the same instance without restarting teardown. `isDestroyed()` remains
`false` during `before:destroy` and is `true` by the time `destroy` is triggered.
If a synchronous lifecycle handler throws, its error propagates and teardown
stops. Later `destroy()` calls do not retry the lifecycle or resume partial
cleanup. Application's asynchronous operation failures follow its separate
lifecycle contract.
Use [`dom:remove`](#domremove-event) or [`before:detach`](#detach-and-beforedetach-events)
for work tied to those transitions. Resources created while detached, or while
attachment monitoring is disabled, also need owner cleanup in `onBeforeDestroy`;
do not rely on a DOM notification that may never occur.
```javascript
import { View } from 'marionette';
const MyView = View.extend({
onBeforeDestroy(view, options) {
console.log(options.foo);
}
});
const myView = new MyView();
myView.destroy({ foo: 'destroy view' });
```
#### `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.
## Wrapping legacy views
Managed children provide Marionette's render and destroy lifecycle themselves.
`supportsRenderLifecycle` and `supportsDestroyLifecycle` are removed; Regions and
CollectionViews do not supply missing lifecycle events or call `remove()` as a
substitute for `destroy()`.
Keep non-Marionette views inside a [Marionette wrapper](/docs/region.md#wrapping-a-non-marionette-view)
that owns their rendering and cleanup. Mixing `Marionette.Events` into a Backbone
View does not make it a supported managed child.
[Canonical source](/docs/markdown/docs/events.class.md) · [Source identity](/docs/manifest.json)
---
Document: docs/events.entity.md
Canonical URL: https://marionettejs.com/docs/entity-events/
Markdown URL: https://marionettejs.com/docs/entity-events.md
Reading SHA-256: 63ba9a71b1af96e01d52a5d8728348872f600b80553144afca5258d5af5e77e4
# Entity events
[`View`, `CollectionView`, and `Behavior`](/docs/classes.md) can declaratively
listen to events from an attached `model` or `collection`. The configured
[`DataApi.subscribe()`](/docs/data-api.md#adapter-contract) owns the entity's
subscription and teardown mechanics; Backbone is optional.
## Handler ownership and arguments
`modelEvents` and `collectionEvents` map entity event names to method names or
function callbacks. Entity arguments pass through unchanged.
- A View or CollectionView handler runs with that View or CollectionView as
`this`.
- A Behavior listens to its owning View's `model` and `collection`, but its
handler runs with the Behavior as `this`. Use `this.view` to reach the owner.
```javascript
import { Behavior, Events, View } from 'marionette';
class Model {}
Object.assign(Model.prototype, Events);
const StatusBehavior = Behavior.extend({
modelEvents() {
this.modelEventsResolutionCount = (this.modelEventsResolutionCount || 0) + 1;
return {
'change:status': 'onStatus'
};
},
onStatus(model, status) {
this.view.behaviorCall = {
arguments: [model, status],
owner: this
};
}
});
const StatusView = View.extend({
behaviors: [StatusBehavior],
modelEvents() {
this.modelEventsResolutionCount = (this.modelEventsResolutionCount || 0) + 1;
return {
'change:status': 'onStatus'
};
},
onStatus(model, status) {
this.viewCall = {
arguments: [model, status],
owner: this
};
}
});
const model = new Model();
const view = new StatusView({ model });
model.trigger('change:status', model, 'ready');
export { Model, model, view };
```
Function callbacks are also supported directly. This configuration fragment
uses the `update(collection, options)` payload from Backbone or `@mnjs/data`;
configure the matching DataApi before supplying that collection:
```javascript
import { View } from 'marionette';
const MyView = View.extend({
collectionEvents: {
update(collection, options) {
console.log('Added models:', options.changes.added);
}
}
});
```
If a View has both entities, Marionette delegates both maps:
```javascript
import { View } from 'marionette';
const MyView = View.extend({
modelEvents: {
'change:status': 'render'
},
collectionEvents: {
update: 'render'
}
});
```
## Resolver and delegation lifecycle
Each map may be a function returning an object. Marionette calls the resolver
with its owner as `this` and no arguments whenever `delegateEntityEvents()`
performs a delegation. The resolved map is cached for the matching
`undelegateEntityEvents()` call.
Initial entity-event delegation happens after the View or CollectionView's
`initialize` method returns. Assigning a different `model` or `collection`
later does not automatically move existing subscriptions. Undelegate while the
old entity is still assigned, replace it, and then delegate the new entity:
```javascript
view.undelegateEntityEvents();
view.model = replacementModel;
view.delegateEntityEvents();
```
Do not use repeated `delegateEntityEvents()` calls as an idempotent refresh;
delegate only after the matching undelegation.
After a View or CollectionView's destruction completes successfully, its tracked
entity subscriptions have been removed. Once destruction starts, its base
`delegateEntityEvents()` returns the same instance without resolving its maps or
delegating the attached Behaviors' maps. A direct
`Behavior#delegateEntityEvents()` call also returns the Behavior without
resolving maps or binding once its owning View's destruction starts. These
guards derive from the host lifecycle only; reusing a Behavior after calling
`Behavior#destroy()` while its host remains live is outside this contract. A
custom override owns its behavior unless it delegates to the guarded base
method. `undelegateEntityEvents()` remains available during teardown so cleanup
can complete.
## Event-map names
Entity-event maps cannot contain an own enumerable `__proto__` event name.
Marionette throws `MarionetteError` code `MN0026` before binding or selectively
unbinding such a map because third-party entity event implementations may not
safely store that name.
Marionette does not reject other names inherited from `Object.prototype`, such
as `constructor` and `toString`. Marionette's Events API supports those names
and continues to support `__proto__`, but third-party emitters may not safely
support every prototype-collision name.
## Backbone entities
A plain `Backbone.Model` or `Backbone.Collection` satisfies the default
subscription protocol for event-only use. The canonical Backbone setup
configures the integration before constructing Marionette consumers;
it also selects Backbone identity, reads, serialization, ordered model
snapshots, and structural observations:
```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 });
```
See [Optional Backbone](/docs/backbone.md) for the integration's exact boundary.
[Canonical source](/docs/markdown/docs/events.entity.md) · [Source identity](/docs/manifest.json)
---
Document: docs/radio.md
Canonical URL: https://marionettejs.com/docs/radio/
Markdown URL: https://marionettejs.com/docs/radio.md
Reading SHA-256: 0c53fa2091a01f0d52c2ea9c1712dc543ef77dd2a83da10087265f34d38e750b
# Radio
Use `Radio` to send events or request values between parts of an application
that do not need a direct reference to each other. Channels keep those messages
organized by name. Import Radio directly from Marionette:
```javascript
import { Radio } from 'marionette';
```
Radio is included in `marionette`; it does not require a separate
`backbone.radio` installation.
The built-in singleton does not share channels with `backbone.radio`. Migrate
all application imports atomically, including code that publishes or requests
outside Marionette classes; mixing both packages creates disconnected buses.
See [Atomic Radio migration](/docs/upgrade-guide.md#atomic-radio-migration).
## Documentation Index
* [Channels](#channels)
* [Events](#events)
* [Requests and Replies](#requests-and-replies)
* [Debugging](#debugging)
* [Channel Lifecycle](#channel-lifecycle)
* [Marionette Integration](#marionette-integration)
## Channels
A channel provides a namespace for events and requests. Retrieve one with
`Radio.channel(name)`:
```javascript
import { Radio } from 'marionette';
const notifications = Radio.channel('notifications');
```
Calling `Radio.channel(name)` again with the same name returns the same channel
instance. A channel name is required. Channel names that match inherited object
properties, such as `toString`, are treated as ordinary channel names.
Use `new Channel(name)` from `@mnjs/radio` for an independent message bus.
It combines Events and Requests but does not join the registry. Its owner must
call `channel.reset()` when finished. `Radio.reset()` covers registered channels.
The named `Channel` export is `Radio.Channel`; an isolated runtime provides its
own constructor at `runtime.Radio.Channel`.
For request/reply alone, import `Requests` from `@mnjs/radio` and compose it
with `Object.assign({}, Requests)`. It adds no event methods or registry.
## Events
Channels provide event-style messaging with methods including `on`, `once`,
`off`, `trigger`, `listenTo`, and `stopListening`.
```javascript
import { Radio } from 'marionette';
const session = Radio.channel('session');
session.on('expired', function(reason) {
console.log(`Session expired: ${ reason }`);
});
session.trigger('expired', 'signed out remotely');
session.off('expired');
```
Use events when zero or more listeners may react to a notification and the
sender does not need a return value.
## Requests and Replies
Channels also provide request/reply messaging. Register one reply with
`reply`, then call it with `request`:
```javascript
import { Radio } from 'marionette';
const account = Radio.channel('account');
const accountService = { currentUser: { id: 'example' } };
account.reply('current:user', function() {
return this.currentUser;
}, accountService);
const currentUser = account.request('current:user');
```
Arguments passed after the request name are passed to the reply handler, and
the handler's return value is returned from `request`. Invocation is synchronous:
a thrown error reaches the caller immediately; a returned Promise is passed
through unchanged and must be awaited or handled by the caller. Radio does not
add cancellation, retries, or error handling.
A named handler takes precedence over a handler registered as `default`.
The default handler receives `(requestName, ...args)`. With neither handler,
`request` returns `undefined` and may emit a debug warning. A non-function value
registered with `reply(name, value)` is returned as-is for each request.
Registering a second reply for the same name replaces the first; it does not
multicast the request.
`reply`, `replyOnce`, and `stopReplying` return the channel or Requests receiver.
A `replyOnce` handler is removed before invocation, including when it throws or
makes a reentrant request. Removing it by its original callback before invocation
also cancels it. Choose ordinary events when several independent listeners need
to react to the same notification.
Only explicitly registered own handlers are eligible for a named request or
the `default` fallback. Names matching inherited object properties, including
`constructor`, `toString`, and `__proto__`, are ordinary request names. Result
maps from object-form or space-separated requests likewise define safe own
string properties. When an object-form key contains multiple space-separated
names, the nested result contributes its own enumerable string and symbol
properties; inherited and non-enumerable properties are ignored.
Use `replyOnce` for a handler that should be removed after its first request.
Use `stopReplying` to remove one or more handlers:
```javascript
account.replyOnce('status:ready', () => true);
account.stopReplying('current:user');
```
The request registration methods retain Backbone.Radio's customization
seams: `replyOnce` installs its wrapper through overridable `reply`, and map or
space-separated `reply`, `replyOnce`, and `stopReplying` calls dispatch each
entry through the corresponding public method. For object-form `request`, the
mapped value is the first handler argument and any arguments after the map are
forwarded after it.
Use requests when one handler owns an operation or when the sender needs a
return value.
## Debugging
Enable Radio debug warnings with `setDebug`:
```javascript
import { Radio } from 'marionette';
Radio.setDebug();
```
Debug mode warns when a request handler is overwritten or an unhandled request
is made. Disable it explicitly when it is no longer needed:
```javascript
Radio.setDebug(false);
```
`Radio.log(channelName, eventName, ...args)` receives activity from `tuneIn()`.
`Radio.debugLog(warning, eventName, channelName)` receives warnings while debug
mode is enabled. Assign either hook to route output to an application logger or
test collector. Both default to console output.
```javascript
import { createMarionette } from 'marionette';
const runtime = createMarionette();
runtime.Radio.debugLog = (warning, eventName, channelName) => {
console.warn({ warning, eventName, channelName });
};
runtime.Radio.setDebug();
```
Hooks belong to each Radio instance and run with that Radio as `this`. Replacing
a hook affects existing channels, including tuned channels. Disabling debug mode
also disables delivery to custom warning hooks. Exceptions from hooks propagate.
Standalone `Channel` and `Requests` imports use the default Radio's warning
configuration; `new runtime.Radio.Channel(name)` uses that runtime's configuration.
## Channel Lifecycle
Channels are shared by name within their Radio runtime and remain available for that
runtime's lifetime. Root imports use one default Radio. Each
[`createMarionette()`](/docs/runtime-isolation.md) call returns an isolated Radio and
channel registry. Clean up handlers when their owning object or feature is destroyed:
```javascript
import { MnObject, Radio } from 'marionette';
const owner = new MnObject();
const channel = Radio.channel('feature');
owner.stopListening(channel);
channel.off(null, null, owner);
channel.stopReplying(null, null, owner);
```
The matching cleanup depends on whether the owner used `listenTo`, `on`, or
`reply` to register the handler.
Call `channel.reset()` to remove all event listeners, listening relationships,
and reply handlers from that channel. `Radio.reset(name)` resets one existing
channel, while `Radio.reset()` resets all existing channels.
Resetting a channel clears its handlers but does not replace the shared channel
instance. Prefer targeted cleanup for long-lived application channels so one
feature does not remove another feature's handlers.
| Operation | Unknown channel | Existing channel |
| --- | --- | --- |
| `Radio.channel(name)` | Creates and registers the channel. | Returns the same channel. |
| Top-level event, request, and tuning methods | Create the channel through `Radio.channel(name)`. | Operate on the same channel. |
| `Radio.reset(name)` | Throws `MarionetteError` with code [MN0021](/docs/diagnostics.md#look-up-a-code) without creating a channel. | Clears handlers and preserves the channel identity. |
| `Radio.reset()` | Does not create channels. | Resets every registered channel without replacing it. |
Only a zero-argument `Radio.reset()` call means reset all. Supplying an empty or
otherwise falsy channel name throws the existing required-name diagnostic
[MN0017](/docs/diagnostics.md#look-up-a-code) without resetting any channel.
## Marionette Integration
`Application` and `MnObject` can bind events and requests to a channel with
`channelName`, `radioEvents`, and `radioRequests`. `getChannel()` returns the
configured channel.
`radioEvents` follows the [entity-event map contract](/docs/common.md#bindevents),
including the `MN0026` rejection of an own enumerable `__proto__` map entry.
The direct Radio Events API continues to support `__proto__` as an event name.
```javascript
import { MnObject, Radio } from 'marionette';
export const Notifications = MnObject.extend({
channelName: 'notifications',
initialize() {
this.messages = [];
},
radioEvents: {
'message:received': 'showMessage'
},
radioRequests: {
'message:count': 'getMessageCount'
},
showMessage(message) {
this.messages.push(message);
},
getMessageCount() {
return this.messages.length;
}
});
export const notifications = new Notifications();
export const channel = Radio.channel('notifications');
const message = { text: 'Hello' };
channel.trigger('message:received', message);
const count = channel.request('message:count');
```
Destroying the Marionette object removes request handlers bound with that
object as their context. The object's event listeners are cleaned up through
the normal Marionette event lifecycle.
## Backbone.Radio comparison
The v5 Radio implementation retains Backbone.Radio's channel messaging model,
but it is not a drop-in replacement for every exported property.
`@mnjs/radio` can be used independently; core re-exports the same default
`Radio` within each module format.
| Area | v5 behavior |
| --- | --- |
| Requests and replies | Named/default handlers, callback context, map and space-separated forms, one-time replies, and selective removal retain the messaging contract. |
| Events and cleanup | Channels use shared Marionette Events. Reset clears handlers and owned listeners while retaining channel identity. Events also provides `triggerMethod`. |
| Debugging | Use `setDebug()` instead of assigning `DEBUG`. `log` and `debugLog` are replaceable per-instance hooks, and the debug toggle gates custom warning hooks too. Removing an absent reply does not warn. |
| Construction and globals | Use `channel(name)` for registered channels, `new Channel(name)` for standalone channels, or the named `Requests` mixin for request/reply alone. `VERSION`, Backbone global installation, and `noConflict()` are not Radio exports. |
| Names and maps | Request maps use own enumerable string keys. Inherited entries are ignored; names such as `__proto__` are supported without changing object prototypes. |
| Reset arguments | Only `reset()` resets all channels. An explicitly supplied empty name is an error; an unknown named channel gets a Marionette diagnostic. |
`test/unit/radio-parity.spec.js` runs shared behavioral scenarios against the
published Backbone.Radio 2.0.0 runtime and Marionette: fallback arguments, flat
values, nested request maps, reentrant and throwing one-time handlers, callback
and context removal, top-level forwarding, and channel/listener cleanup.
The extraction was also checked against the upstream request, channel, forwarding,
tuning, and debug tests at
[Backbone.Radio commit 7a58ade](https://github.com/marionettejs/backbone.radio/tree/7a58ade84bedb5551c2e12bdd3434d0fd6b1bdbd/test/unit).
That comparison adapts private registry names and the old debug toggle; tests
requiring removed public APIs are differences, not claims of full compatibility.
One intentional correction relative to the published 2.0.0 bundle is cancellation
of `replyOnce` by its original callback: `stopReplying(name, callback)` removes
the pending reply in v5. The published bundle and inspected upstream source
leave it registered. This follows the callback-identity behavior of
Backbone.Events `once`/`off`. The comparison test records the difference
explicitly instead of claiming exact parity.
[Canonical source](/docs/markdown/docs/radio.md) · [Source identity](/docs/manifest.json)
---
Document: docs/utils.md
Canonical URL: https://marionettejs.com/docs/utils/
Markdown URL: https://marionettejs.com/docs/utils.md
Reading SHA-256: d7ea4080dad95c0bb3283a8461d569584b86e3f9cd7daa0faaa469798e3e777a
# Marionette Utility Exports
Marionette exports the standalone utilities and package facts that do not require a
framework instance. Common framework conventions such as `bindEvents`, `getOption`,
`mergeOptions`, `normalizeMethods`, and `triggerMethod` are documented as
[instance methods](/docs/common.md).
The v4 target-first exports also adapted these conventions to arbitrary plain
objects. That adapter is not part of v5. Import reusable helpers from
[`@mnjs/utils`](/docs/common.md#shared-helpers) when a plain component needs them;
extend `MnObject` when it needs Marionette's initialization and cleanup lifecycle.
Do not borrow a framework prototype solely to obtain a helper.
## Documentation Index
* [extend](#extend)
* [VERSION](#version)
## extend
`extend` is Marionette's owned, standalone implementation of its classic
pseudo-class extension convention. Assign it to a constructor, then call it as
a method so that constructor is the parent. Marionette's extendable classes
already expose this method.
```javascript
import { extend } from 'marionette';
function Service(name) {
this.name = name;
}
Service.extend = extend;
const SpecialService = Service.extend({
label() {
return `special:${this.name}`;
}
}, {
kind: 'special'
});
const service = new SpecialService('api');
export { Service, SpecialService, extend, service };
```
The child inherits the parent's prototype and static properties. Prototype
properties are supplied by the first argument and optional static properties
by the second. See the [v4 compatibility ledger](/docs/migration-from-v4.md#compatibility-ledger)
for the v5 input-copying boundary.
## VERSION
`VERSION` is the installed Marionette package version. Marionette also uses it
when constructing versioned diagnostic documentation URLs; exporting it does
not imply that a corresponding website deployment is available.
```javascript
import { VERSION } from 'marionette';
export { VERSION };
```
[Canonical source](/docs/markdown/docs/utils.md) · [Source identity](/docs/manifest.json)
---
Document: docs/marionette.mnobject.md
Canonical URL: https://marionettejs.com/docs/mn-object/
Markdown URL: https://marionettejs.com/docs/mn-object.md
Reading SHA-256: c92fd00483055350c4696082070a77361ec33fdc1b3d503e2a57175a1141e8d9
# Marionette.MnObject
Use `MnObject` for objects that need Marionette events and cleanup without a
DOM element. It provides `initialize`, options, the Events API, a unique `cid`,
and `extend`, with no Backbone dependency.
`MnObject` includes:
- [Common Marionette Functionality](/docs/common.md)
- [Class Events](/docs/class-events.md#mnobject-events)
- [Radio API](/docs/radio.md#marionette-integration)
- [State ownership](/docs/state.md#borrowed-and-owned-sources)
## Documentation Index
* [Instantiating a MnObject](#instantiating-a-mnobject)
* [Unique Client ID](#unique-client-id)
* [Destroying a MnObject](#destroying-a-mnobject)
* [Basic Use](#basic-use)
* [v4 Migration](#v4-migration)
## Instantiating a MnObject
Constructor options are shallow-copied into `this.options`. Own enumerable
`channelName`, `radioEvents`, `radioRequests`, and `stateEvents` options with values other than
`undefined` are also attached directly to the instance. Other options remain
available through `this.options` and `getOption` unless explicitly merged.
The channel options use Marionette's built-in [`Radio`](/docs/radio.md); see that guide
for the separate `backbone.radio` migration boundary.
A supplied `state` source is borrowed. A source returned by `createState(options)`
is owned and created lazily; `getState()` returns the exact source. Configured
`stateEvents` subscribe after `initialize`. Destruction removes those
subscriptions and disposes owned State through the selected StateApi. See
[State](/docs/state.md) before enabling observable State events.
```javascript
import { MnObject } from 'marionette';
const myObject = new MnObject({ channelName: 'tasks' });
myObject.channelName; // 'tasks'
```
## Unique Client ID
The `cid` or client id is a unique identifier automatically assigned to MnObjects
when they're first created and by default is prefixed with `mno`.
You can modify the prefix for `MnObject`s you `extend` by setting the `cidPrefix`,
which should be a non-empty string when customized. IDs generated with the same
prefix by one loaded copy of Marionette are unique, including when different
Marionette types use that prefix. Treat the complete `cid` as opaque: its numeric
suffix and allocation order are not API, and its sequence is not coordinated with
IDs generated by Underscore or Backbone.
The [v4-to-v5 migration ledger](/docs/migration-from-v4.md#compatibility-ledger)
records the sequence-ownership rationale.
```javascript
import { MnObject } from 'marionette';
const MyFoo = MnObject.extend({
cidPrefix: 'foo'
});
const foo = new MyFoo();
foo.cid.startsWith('foo'); // true
```
## Destroying a MnObject
### `destroy`
On successful completion of its lifecycle, `destroy` removes subscriptions the
instance made with `listenTo`, releases its owned Radio event subscriptions and
replies, cleans up State, and returns the MnObject synchronously. Returned Promises
from destruction hooks are not awaited. It does not reset the shared Radio channel or
remove unrelated channel handlers. Listeners registered directly on the
instance with `on` are not removed automatically. If a lifecycle callback
throws, cleanup that has not yet run may be skipped; the failure boundaries are
described below.
Invoking `destroy` triggers `before:destroy` and `destroy` events and their
[corresponding `onBeforeDestroy` and `onDestroy` methods](/docs/events.md#onevent-binding).
Each receives the MnObject followed by the `options` passed to `destroy`.
While a `destroy()` call is in progress, nested calls from either lifecycle
event return the same MnObject without restarting teardown. Calls after
destruction also return the same MnObject without repeating the lifecycle.
`Application` has an asynchronous destruction lifecycle; see its
[reference](/docs/application.md#application-lifecycle).
`isDestroyed()` is `false` during `before:destroy` and `true` during `destroy`.
If a lifecycle handler throws, the error propagates and stops destruction.
The destruction guard remains set; later `destroy()` calls do not restart
hooks or resume cleanup.
A custom override that mutates owned state before calling the base `destroy`
method is outside this guard. See the
[v4-to-v5 compatibility ledger](/docs/migration-from-v4.md#compatibility-ledger) for
the override boundary.
```javascript
import { MnObject } from 'marionette';
// define a mnobject with an onBeforeDestroy method
const MyObject = MnObject.extend({
onBeforeDestroy(currentObject, options) {
// put other custom clean-up code here
}
});
// create new MnObject instances
const obj = new MyObject();
const source = new MnObject();
// add some event handlers
obj.on('before:destroy', function(currentObject, options) {
console.log(options.foo);
});
obj.listenTo(source, 'bar', function() {});
// trigger the lifecycle and stop listening to source
obj.destroy({ foo: 'bar' });
```
### `isDestroyed`
This method will return a boolean indicating if the mnobject has been destroyed.
```javascript
import { MnObject } from 'marionette';
const obj = new MnObject();
obj.isDestroyed(); // false
obj.destroy();
obj.isDestroyed(); // true
```
## Basic Use
Selections is a simple MnObject that manages a selection of things.
Because Selections extends from MnObject, it inherits `initialize` and the
[Events API](/docs/events.md).
```javascript
import { MnObject } from 'marionette';
const Selections = MnObject.extend({
initialize() {
this.selections = {};
},
select(key, selection) {
this.selections[key] = selection;
this.triggerMethod('select', key, selection);
},
deselect(key, selection) {
delete this.selections[key];
this.triggerMethod('deselect', key, selection);
}
});
const selections = new Selections();
const truck = { name: 'Dump truck' };
// use the inherited Events API
selections.on('select', function(key, selection) {
console.log(selection);
});
selections.select('toy', truck);
```
## v4 Migration
v5 exports `MnObject` by name from `marionette`. The historical `Object` alias
and v4 default namespace export are removed. See the
[v4-to-v5 migration ledger](/docs/migration-from-v4.md) for the replacement paths.
[Canonical source](/docs/markdown/docs/marionette.mnobject.md) · [Source identity](/docs/manifest.json)
---
Document: docs/diagnostic-catalog.md
Canonical URL: https://marionettejs.com/docs/diagnostics/
Markdown URL: https://marionettejs.com/docs/diagnostics.md
Reading SHA-256: 060b1d0808d63c1934369d6ee65814b670306d2370a7516702b58c37c58fbd6e
# Diagnostic catalog
Marionette uses one machine-readable catalog to identify framework invariants across
runtime diagnostics, static analysis, development and test tooling, documentation,
and the public agent benchmark. The catalog is stored in
`config/diagnostics/catalog.json`, and its executable contract is
`config/diagnostics/catalog.schema.json`.
The catalog is static project metadata. Production entrypoints must not import the
catalog, and the catalog is not part of the production package surface. Runtime
diagnostics may embed a compact catalog code, but they must not load the full catalog.
Schema version 2 adds explicit retired identities without restoring their emissions.
## Look up a code
Read the [machine-readable catalog](/docs/source/config/diagnostics/catalog.json), find the
entry by `code`, and read its `remediation`. This file is included in packaged
docs for offline lookup. The website also provides a
[diagnostic reference](/errors/index.md).
## Runtime error contract
Framework invariant failures use the public `MarionetteError` class:
```javascript
import { MarionetteError, View } from 'marionette';
try {
new View({ template: false }).showChildView('missing', new View());
} catch (error) {
if (error instanceof MarionetteError && error.code === 'MN0020') {
// Handle the missing named Region.
}
}
```
`MarionetteError` extends the native `Error` class and exposes `name`, `code`,
`message`, `stack`, and the existing `url` property. The code is the stable lookup
key for the repository-generated diagnostic reference. Error names preserve useful
framework categories such as `ViewError`, `RegionError`, and `CollectionViewError`.
Messages and legacy URLs are explanatory prose and are not machine contracts.
Production errors copy only supported Error fields and the compact code. They do not
import the catalog or perform runtime catalog lookup. Engines with
`Error.captureStackTrace` use it; other engines retain the native fallback stack.
## Entry contract
Every entry has these fields:
- `code`: an opaque identifier in the form `MN0001`. The number does not encode the
diagnostic category, object, severity, or implementation order.
- `slug`: a unique lowercase kebab-case name used by tools and people.
- `status`: `defined` before the code is emitted, `active` once a supported surface
emits it, `deprecated` after it has a replacement, or `retired` after the
diagnostic is removed without a replacement. Retired entries remain cataloged
permanently but cannot be emitted.
- `category`: the kind of contract involved: `configuration`, `communication`,
`dom`, `lifecycle`, or `ownership`.
- `severity`: `error`, `warning`, or `info`, following the model below.
- `objects`: the public Marionette objects involved in the invariant.
- `remediation`: concise guidance for correcting the violation. This is human prose
and may improve without changing the diagnostic identity.
- `docsAnchor`: the permanent version-neutral documentation route. It is always
`/errors//`.
- `surfaces`: the places that report the diagnostic, or historically reported it
for a retired entry: `runtime`, `lint`, `development`, `test`, or `benchmark`.
- `benchmarkCategory`: the public benchmark category used to classify the violation.
A deprecated entry also has `replacementCode`, which must identify another catalog
entry. Defined, active, and retired entries cannot declare a replacement.
### Severity model
- `error` means the invariant is violated and the requested operation cannot safely
continue. Runtime surfaces throw; lint and validation surfaces fail their check;
benchmark runs count the violation as incorrect.
- `warning` means execution can continue but the usage is unsafe, deprecated, or
likely unintended. Tools report it without changing runtime control flow; release
evidence must explicitly approve or eliminate it.
- `info` records deterministic context or guidance without indicating incorrect
behavior. It does not fail an operation, check, or benchmark result by itself.
For a retired entry, the stored severity and surfaces retain the diagnostic's
historical classification. The generated reference labels those values as historical
for display only. The `retired` status is authoritative: the entry is not a current
error, warning, informational report, or supported-surface mapping.
## Stability policy
Codes and slugs are unique and are never reassigned. The numeric portion of a code is
allocated monotonically, gaps are allowed, and entries are never renumbered to close
a gap. Deprecation retains both the catalog entry and its `/errors//` route and
names the replacement. Retirement retains the identity and route without implying a
replacement. Deletion and reuse are not supported.
Before stable v5, defined catalog fields may be revised through reviewed changes.
After stable v5, active, deprecated, and retired entries follow these rules:
- adding a diagnostic or deprecating one is a minor change;
- retiring an active diagnostic changes supported behavior and requires
major-version review;
- clarifying remediation without changing its meaning is a patch change;
- changing the meaning of a machine-readable field or the schema is a breaking
change and requires a new schema version and major-version review;
- deleting or reusing a published code, slug, or diagnostic route is prohibited.
Messages are deliberately not catalog identifiers. Human-readable runtime messages
may improve while the code and slug remain stable.
## Surface mappings
Runtime diagnostics declare their catalog identifier as a literal `code` property.
Custom ESLint rules under `eslint-rules/` default-export an object literal whose
`meta` object declares exactly one literal `diagnosticCode`. Benchmark and test
results record the same code rather than copying the diagnostic meaning into a
second identifier.
Runtime diagnostic options and lint-rule metadata cannot use computed keys, spreads,
or duplicate mapping properties. This keeps the emitted code statically decidable.
A `defined` entry must move to `active` in the same change that first emits it.
A retired entry cannot be emitted or mapped by a supported surface.
`npm run check:diagnostics` derives the shipped source graph from the production
Rollup inputs, rejects runtime codes or lint-rule mappings that are not in the
catalog, and rejects a lint rule without a mapping. Documentation routes are
generated from the catalog and then checked by `npm run docs:check`; they are not
maintained as a second hand-written list.
## Initial scope
The initial active entries describe only deliberate errors already thrown by the
framework. Retired entries reserve identities that were formerly active; they do not
reserve codes for planned validation. Defined entries likewise are not placeholders
for incidental JavaScript exceptions or benchmark hypotheses. New invariants receive codes when their
behavior and remediation are implemented and reviewed.
The generated [diagnostic reference](/errors/index.md) lists the current catalog directly
from the machine-readable source. A shared invariant has one code even when more
than one framework object reports it.
## Argument types and runtime diagnostics
Marionette trusts the declared shapes of callbacks, arrays, View instances,
configuration objects, and adapter methods. TypeScript consumers receive errors
for unsupported shapes during type checking. JavaScript consumers follow the same
documented contracts; unsupported arguments have no guaranteed runtime diagnostic.
Runtime diagnostics remain for ownership conflicts, invalid collection identity,
missing DOM targets, unresolved handler names, and incompatible data sources.
Retired shape-diagnostic codes remain listed for historical reference and are not
reused. See [contributing](https://github.com/marionettejs/marionette/blob/b06750c507494441f0b2298766b70087e45346a2/CONTRIBUTING.md#runtime-checks-and-types) for the rule
used when adding or removing checks.
[Canonical source](/docs/markdown/docs/diagnostic-catalog.md) · [Source identity](/docs/manifest.json)
---
Document: docs/public-api.md
Canonical URL: https://marionettejs.com/docs/public-api/
Markdown URL: https://marionettejs.com/docs/public-api.md
Reading SHA-256: 7fc7fc3446f2c9951c47055c524f4520e5d205ba87e4764b52c022d8eebd64ee
# Public API index
Use this index to identify the supported import and follow its behavior contract.
The `marionette` package has named exports; it has no default export. Import
optional integrations from their documented package subpaths, never from `src/`
or generated internal files.
## Core runtime exports
| Export | Purpose and reference |
| --- | --- |
| `View` | [Render and own one part of the interface](/docs/view.md). |
| `CollectionView` | [Own ordered child Views](/docs/collection-view.md). |
| `Region` | [Show, replace, detach, or destroy a current View](/docs/region.md). |
| `Application` | [Coordinate asynchronous feature lifecycle and child Applications](/docs/application.md). |
| `Behavior` | [Share host View interactions and lifecycle](/docs/behavior.md). |
| `MnObject` | [Own nonvisual events, State, and synchronous cleanup](/docs/mn-object.md). |
| `Events` | [Compose the event/listening contract](/docs/events.md#events-api). |
| `Radio` | [Use the default runtime's named message channels](/docs/radio.md). |
| `DataApi`, `setDataApi` | [Read and observe the selected data source](/docs/data-api.md). |
| `StateApi`, `setStateApi` | [Observe State and dispose owned sources](/docs/state.md). |
| `DomApi`, `setDomApi` | [Create, query, attach, and update DOM](/docs/dom-api.md). |
| `setRenderer` | [Configure synchronous template evaluation](/docs/rendering.md#using-a-custom-renderer). |
| `setEventDelegator` | [Configure DOM event registration and cleanup](/docs/dom-interactions.md#eventdelegator-adapter). |
| `createMarionette` | [Create independent classes, configuration, and Radio](/docs/runtime-isolation.md). |
| `monitorViewEvents` | [Bridge lifecycle notifications for supported custom Views](#monitorvieweventsview). |
| `extend` | [Extend a function constructor](/docs/utils.md#extend). |
| `MarionetteError` | [Inspect a framework invariant failure](/docs/diagnostics.md). |
| `VERSION` | [Read the package version](/docs/utils.md#version). |
[Configuration method contracts](/docs/runtime-isolation.md#configuration-method-contract)
identify which classes each setter affects, its return value, and its scope.
Choosing one provider does not configure the other providers.
## `monitorViewEvents(view)`
This synchronous helper installs lifecycle listeners on a supported custom View
and returns `undefined`. It propagates attachment and detachment notifications
to managed children and derives `dom:refresh`/`dom:remove` from render and
attachment state. Repeating the call does not install duplicate monitoring;
`monitorViewEvents: false` skips installation.
Marionette Views are monitored automatically. This helper is for integrations
that implement the [supported View lifecycle](/docs/region.md#wrapping-a-non-marionette-view),
including event methods and managed-child access. It is not a MutationObserver:
appending arbitrary DOM does not notify it. Prefer a Marionette wrapper View
for third-party widgets so ownership and cleanup remain explicit.
## Companion packages
| Import | Public surface | Reference |
| --- | --- | --- |
| `@mnjs/data` | `Model`, `Collection`, `DataApi`, `StateApi`, `triggerMethod` | [Native observable data](/docs/data-package.md) |
| `@mnjs/radio` | `Radio`, `createRadio`, `Channel`, `Requests` | [Standalone Radio](/docs/radio-package.md) |
| `@mnjs/utils` | Shared events, bindings, option, inheritance, and event-building helpers | [Utility exports](/docs/utils-package.md) |
| `@mnjs/adapters/backbone` | Default Backbone data/State adapter | [Backbone integration](/docs/backbone.md) |
| `@mnjs/adapters/xstate` | Default `createXStateActorApi` factory | [XState integration](/docs/data-api.md#xstate-actors) |
| `@mnjs/adapters/dom/jquery` | Default jQuery DomApi | [jQuery DOM](/docs/dom-api.md#optional-jquery-adapter) |
| `@mnjs/adapters/dom/morphdom` | Default Morphdom DomApi | [DOM update adapters](/docs/rendering.md#rendering-to-dom) |
| `@mnjs/adapters/dom/lit-html` | Default Lit DomApi | [DOM update adapters](/docs/rendering.md#rendering-to-dom) |
Add a companion package as a direct dependency when application code imports it.
Match Marionette package versions during prereleases. Optional integrations need only
their selected peers; see [Choosing integrations](/docs/choosing-integrations.md).
## TypeScript exports
Core also exports types for class instances and constructors, class configuration,
Region definitions and show options, Application readiness context, DOM events
and triggers, UI bindings, Behavior definitions, event and request contracts, and
provider contracts (`DataApiContract`, `DomApiContract`, `StateApiContract`,
`EventDelegator`, and `Renderer`). Use `import type` for these names. They do not
create runtime values or install a provider.
The package's declarations are the exact signature reference. Keep inferred
subclass types when possible rather than annotating an extended View as the broad
base instance type and losing its application-specific methods.
[Canonical source](/docs/markdown/docs/public-api.md) · [Source identity](/docs/manifest.json)
---
Document: packages/radio/readme.md
Canonical URL: https://marionettejs.com/docs/radio-package/
Markdown URL: https://marionettejs.com/docs/radio-package.md
Reading SHA-256: a0461bec43fb673ce109ae5d1902a78aeb8eb011ef53f00a1eb4a7121a261bb7
# @mnjs/radio
Named channels for events and request/reply, usable without Marionette core or a DOM.
```sh
npm install @mnjs/radio@5.0.0-beta.1
```
```js
import { Radio, createRadio } from '@mnjs/radio';
const channel = Radio.channel('app');
channel.reply('title', () => 'Hello');
channel.on('refresh', () => console.log('Refreshing'));
channel.request('title');
channel.trigger('refresh');
const isolatedRadio = createRadio();
```
`Radio` is the default instance also exported by `marionette`. Within the same
module format and package installation, either import reaches the same channels.
`createRadio()` creates an independent channel registry. Each `createMarionette()`
runtime also owns its own Radio instance; use that runtime's `Radio` when binding
its objects and applications.
The package depends on `@mnjs/utils`, which supplies Events and shared
helpers. It does not depend on core. ESM and CommonJS exports include `Radio`,
`createRadio`, `Channel`, `Requests`, and their public types. ESM and CommonJS each have
their own default instance; do not mix the two formats to share a channel registry.
Radio, utils, data, adapters, and core are versioned and released together.
## Standalone messaging
```js
import { Channel, Requests } from '@mnjs/radio';
const local = new Channel('editor');
local.on('save', () => console.log('Saved'));
local.reply('title', 'Untitled');
const service = Object.assign({}, Requests);
service.reply('ready', true);
```
`new Channel(name)` creates an independent Events-and-Requests object. It is not
registered with Radio; call its `reset()` to remove its handlers and owned
listeners. Two standalone channels with the same name are still separate objects.
`Radio.reset()` only covers channels obtained through `Radio.channel(name)`.
The named `Channel` export is `Radio.Channel`. Use `new isolatedRadio.Channel(name)`
when a standalone channel should share a particular Radio instance's logging
configuration. `Requests` adds only request/reply methods to its receiver; it uses
the default Radio's warning configuration.
## Logging
Assign `radio.log(channelName, eventName, ...args)` to receive activity from
`tuneIn()`, and `radio.debugLog(warning, eventName, channelName)` to receive
diagnostics. The defaults write to the console.
```js
const radio = createRadio();
radio.log = (channel, event, ...args) => console.log({ channel, event, args });
radio.debugLog = (warning, event, channel) => console.warn({ warning, event, channel });
radio.setDebug();
radio.tuneIn('app');
```
Each Radio instance owns its hooks. They run with that Radio as `this`, and
existing channels use the current hook, even when it is replaced after `tuneIn()`.
`setDebug(false)` suppresses warning delivery to custom hooks too. Standalone
channels use their constructor's Radio configuration; the shared default
Requests mixin uses the default Radio. Hook exceptions propagate to the caller.
[Canonical source](/docs/markdown/packages/radio/readme.md) · [Source identity](/docs/manifest.json)
---
Document: packages/utils/readme.md
Canonical URL: https://marionettejs.com/docs/utils-package/
Markdown URL: https://marionettejs.com/docs/utils-package.md
Reading SHA-256: 1c4030cc3fe442d93b97e44c5aab30341dc08ac3d02308185b5aba2ce7b56901
# @mnjs/utils
The small helpers behind Marionette, available for your own components.
Marionette and `@mnjs/data` import these same implementations.
```bash
npm install @mnjs/utils@5.0.0-beta.1
```
Use the same version for all Marionette packages. Core and data
install utils automatically as a regular dependency. Add it directly when your
application imports it.
## Building a component
Methods such as `getOption`, `normalizeMethods`, and `triggerMethod` use their
receiver as the component. Mix them into a prototype or call them with `.call()`.
```js
import { Events, getOption, normalizeMethods, triggerMethod } from '@mnjs/utils';
const component = {
...Events,
getOption,
normalizeMethods,
triggerMethod,
options: { label: 'Inbox' },
onOpen() {
return this.getOption('label');
}
};
component.triggerMethod('open'); // 'Inbox'
component.normalizeMethods({ open: 'onOpen' });
```
## Events
`Events` is the shared event implementation used by Marionette, Radio, and native
data. Mix it into an object with `Object.assign({}, Events)` to use `on`, `off`,
`trigger`, `listenTo`, and `stopListening` without core.
## Helpers
Use object spread or `Object.assign` for ordinary copying and composition.
Inherited enumerable parent statics are copied only inside `extend`.
- `getValue(object, key, fallback)` reads a value and calls it on the object if it
is a function. `getOption` reads from `this.options`, then the receiver.
- `mergeOptions(options, keys)` copies selected options onto the receiver.
- `normalizeMethods(map)` resolves method names on the receiver.
`resolveMethod(context, method, name)` resolves one handler.
- `bindEvents` and `unbindEvents` use the receiver's listening methods.
`bindRequests` and `unbindRequests` register or remove channel replies with
the receiver as their context. `normalizeBindings(context, map)` resolves an
event map without subscribing.
- `triggerMethod(eventName, ...args)` invokes the matching `onEventName` method
and triggers the event.
- `extend` is the function-constructor inheritance helper used by Marionette.
- `MarionetteError` is the same error constructor exported by Marionette.
- `isString` recognizes primitive and boxed strings. `setProperty` assigns a
property, treating `__proto__` as an own data property.
ES modules, CommonJS, and TypeScript declarations are included. The package has
no runtime dependencies and declares no side effects. Bundlers can retain only
the imported helpers. Marionette's standalone UMD bundles include these helpers;
module consumers share the installed package.
Event-building helpers `buildEventArgs`, `eventSplitter`, `callHandler`, and
`onceWrap`, plus `uniqueId`, are shared by core and Radio.
[Canonical source](/docs/markdown/packages/utils/readme.md) · [Source identity](/docs/manifest.json)
---
Document: docs/migration-from-v4.md
Canonical URL: https://marionettejs.com/docs/migration-from-v4/
Markdown URL: https://marionettejs.com/docs/migration-from-v4.md
Reading SHA-256: 7d62a1d35855c2e2889c479c6cafcd4c0909cc1d8a95d41547da1239e69aaede
# Marionette v4 to v5 Compatibility Ledger
This ledger records the public compatibility boundary between Marionette v4
and v5. It is a reference, not the full procedural upgrade guide. Detailed
upgrade steps that are not already documented are tracked in
[the stable-release documentation issue](https://github.com/marionettejs/marionette/issues/147).
Status values describe the v5 outcome:
- **Preserved**: the supported public behavior remains available.
- **Changed**: the public behavior remains relevant but has a different contract.
- **Removed**: the v4 behavior is not supported in v5.
- **Added**: v5 provides a new public capability with no core v4 equivalent.
- **Optional**: the behavior is available only through an explicit opt-in.
- **Renamed**: the capability remains under a different name.
- **Documented**: the public extension point is retained and called out here.
If your application imports directly from @mnjs/radio, declare version 5.0.0-beta.1 as a direct dependency in your application package.json. Do not rely on Marionette’s transitive dependency.
## Compatibility ledger
| Area | v4 behavior | v5 behavior | Status | Migration note |
| --- | --- | --- | --- | --- |
| Package name | Installed as `backbone.marionette`. | Published as `marionette`. | Changed | Replace the package name. See [Installing Marionette](/docs/installation.md#install). |
| Install command | `npm install backbone.marionette` installed Marionette under the v4 name. | Install core with `npm install marionette@5.0.0-beta.1`; add optional peers only when used. | Changed | See [peer dependencies](/docs/installation.md#peer-dependencies). |
| Default export namespace | Namespace-style default import usage was supported. | A default namespace export is not supported. | Removed | Use named imports. See [Quick start](/docs/installation.md#quick-start); final migration guidance is tracked in [#147](https://github.com/marionettejs/marionette/issues/147). |
| Named exports | Classes and utilities were available as named exports. | Named exports are the supported module API. | Preserved | Import only what is needed, for example `import { View, Region } from 'marionette';`. |
| Feature flags | `setEnabled` and `isEnabled` configured one module-global registry, including `childViewEventPrefix`, `triggersPreventDefault`, `triggersStopPropagation`, `DEV_MODE`, and application-owned names. | The registry and both named exports are removed. Child event prefixes remain configurable per View. Trigger default prevention and propagation remain configurable per trigger. | Removed | Remove flag calls and imports. The disabled `triggersPreventDefault` and `triggersStopPropagation` flags globally inverted trigger defaults and have no global replacement; set `preventDefault: false` or `stopPropagation: false` on each affected trigger. Set `childViewEventPrefix` on the owning View, and move application-owned values to Application State or explicit application configuration. Future deprecations use cataloged diagnostics instead of `DEV_MODE`. |
| Backbone dependency | Backbone was a required runtime dependency and supplied core model, collection, event, and view behavior. | Marionette core does not import Backbone. Plain objects and arrays use the neutral DataApi; Backbone is an explicit integration. | Optional | Install `@mnjs/adapters` and configure its `BackboneApi` with `setDataApi()` for model/collection use and `setStateApi()` separately for Backbone state observation. See [Optional Backbone](/docs/backbone.md). |
| Model and collection data | Core read Backbone-specific `cid`, `attributes`, `get`, `models`, `indexOf`, and structural event payloads directly. | Core reads identity, values, serialization, ordered model snapshots, subscriptions, and structural changes through DataApi. | Changed | Use plain objects and arrays with the default adapter, configure `BackboneApi` for Backbone, or configure a custom adapter with `setDataApi`. See [Data API](/docs/data-api.md). |
| Serialized collection template property | A View with a collection and no model supplied the result of `serializeCollection()` to the template as `items`. | The template receives that result as `models`, matching the DataApi vocabulary while remaining distinct from the raw ordered snapshot returned by `DataApi.models(collection)`. Default serialization returns an array of serialized values; an override may return another shape. The pre-stable `items` property is removed. | Changed | Replace collection-template reads and destructuring of `items` with `models`; do not retain a fallback for both names. |
| Region display input | `Region#show` and `View#showChildView` accepted a View instance, template function, string, or View-options object. Non-View values implicitly constructed a base Marionette View. | Both methods require a Marionette View instance. The public types require an instance; Regions do not allocate hidden Views or provide a custom diagnostic for unsupported input shapes. | Changed | Construct the intended View explicitly and pass the instance. Replace strings or template functions with `new View({ template: () => content })`, and wrap former View-options objects with `new View(options)`. |
| Local state | Core did not provide a first-class state-source composition contract; applications commonly used a Backbone model or separate mixin. Toolkit mixed Backbone-backed `getState(attr)`, `setState`, `toggleState`, `hasState`, and reset helpers into several owners. | `Application`, `MnObject`, `View`, `CollectionView`, and `Behavior` compose an exact source through borrowed `state` or owned `createState(options)`. `getState()` returns that source, and StateApi observes `stateEvents`. The v5 alpha concrete `State` export is removed. | Changed | For simple local values, return a plain object from [`createState()`](/docs/state.md) and use property access. For reactive state, supply the provider's source and configure its StateApi. Move mutation to the source's native API; core adds no universal mutation wrappers. |
| Explicit Backbone integration | Backbone integration was applied as part of the v4 dependency relationship. | `@mnjs/adapters/backbone` provides one combined DataApi and StateApi adapter without modifying Backbone objects, prototypes, or native event behavior. | Optional | Pass `BackboneApi` to the selected runtime's `setDataApi()` and `setStateApi()` methods before constructing Marionette owners that consume those sources. See [Optional Backbone](/docs/backbone.md). |
| jQuery dependency | jQuery commonly backed Backbone view and Marionette DOM behavior. | Marionette core does not import jQuery. | Optional | Install jQuery only when using `@mnjs/adapters/dom/jquery`. See [jQuery DOM adapter is optional](/docs/installation.md#jquery-dom-adapter-is-optional). |
| Optional jQuery DomApi | jQuery-backed DOM operations were part of the common v4 stack. | The `@mnjs/adapters/dom/jquery` subpath provides explicitly selected jQuery-backed DOM methods without adding `$el` to core. | Optional | Configure it at app boot with `setDomApi`. See [jQuery DOM compatibility](/docs/upgrade-guide.md#jquery-dom-compatibility). |
| `$el` | Views and Behaviors exposed a jQuery wrapper. | Core and adapters do not create `$el`; Views keep a fixed root. | Changed | Assign `this.$el = $(this.el)` in the View, CollectionView, or Behavior `initialize()` when needed. See [jQuery DOM compatibility](/docs/upgrade-guide.md#jquery-dom-compatibility). |
| `view.$(selector)` | Returned a jQuery collection in the common Backbone/jQuery configuration. | Delegates to `DomApi.findEl`, which returns a native `NodeList` by default or a jQuery collection with the optional adapter. | Changed | Prefer native collection APIs, or opt into `@mnjs/adapters/dom/jquery`. See [jQuery DOM compatibility](/docs/upgrade-guide.md#jquery-dom-compatibility). |
| CollectionView `attachHtml` container | The second override argument was a jQuery-wrapped `$container`. | The second argument is the native child container element, equal to the CollectionView's `el` unless `childViewContainer` selects another element. | Changed | Update overrides to accept `attachHtml(els, container)` and pass the native `container` to DomApi operations. Do not depend on jQuery collection methods or restore a dual-shape argument. |
| Region element resolution | Construction resolved selector strings through public `Region#getEl` before `initialize`; `getEl` returned a jQuery collection, and custom DomApi adapters could implement `getEl(selector)`. | Construction preserves the configured selector for `initialize` and defers public `Region#getEl` dispatch until the first DOM operation. `Region#getEl` returns the first matching native DOM element. `DomApi#getEl` is removed; selector lookup delegates to `findEl(context, selector)`. | Changed | Do not rely on constructor-time DOM lookup or `getEl` side effects. Make Region `getEl` overrides return one native DOM element. Replace DomApi `getEl` overrides with `findEl`, returning an array-like collection whose first entry is the matched element. |
| Region `el` input | Accepted a selector string, DOM element, or jQuery-wrapped element. | Selector-string and DOM-element support are preserved. A jQuery collection is rejected even when the optional DomApi adapter is selected. | Changed | Pass the native element, such as `wrappedElement[0]`. Region remains the Marionette mount-point abstraction. See [View `el` is element-only](/docs/upgrade-guide.md#view-el-is-element-only). |
| View `el` | Selector strings and jQuery-wrapped elements commonly worked through Backbone and jQuery. | `View` accepts a DOM element only and throws a migration hint for strings or wrappers. | Changed | Resolve a selector with `document.querySelector(...)` or unwrap a jQuery collection with `[0]`. See [View `el` is element-only](/docs/upgrade-guide.md#view-el-is-element-only). |
| View root replacement | `setElement()` transferred a View to another element. | View and CollectionView roots are fixed at construction; `setElement()` is removed and the public instance `el` is readonly. | Removed | Supply `el` at construction. For a different root, destroy the old View and construct a new owner. See [View roots are fixed at construction](/docs/upgrade-guide.md#view-roots-are-fixed-at-construction). |
| View DOM attributes | View attribute cloning could copy inherited enumerable properties. Attributes were applied through jQuery. | Attribute maps contribute own enumerable string keys and use DOM attribute names. `renderAttributes()` refreshes root attributes without rendering content. Only explicit `null` removes an attribute; undefined and omitted entries leave it untouched. Other values use native string conversion. | Changed | Use own attribute declarations and `null` for removal. For boolean HTML attributes use `disabled: isDisabled ? '' : null`; `false` becomes the string `"false"`. Set live form properties explicitly. Keep using the View-level `className` option; inside `attributes`, use `class` and `for`. |
| CollectionView `emptyView` | Direct falsy values and resolvers returning `undefined`, `null`, or `false` disabled the empty view; other invalid definitions were skipped silently or failed with incidental errors. | Omitted values, direct `undefined`, `null`, or `false`, and resolvers returning those values disable the empty view. The public types describe these alternatives; no custom shape diagnostic is emitted. | Preserved | Existing conditional resolvers require no migration; return a View class or a supported disabled value. |
| Detach semantics | jQuery detach operations preserved jQuery listener and data bookkeeping for detached nodes. | The native DomApi removes nodes without cleaning their listeners or jQuery data; the optional adapter delegates to jQuery detach operations. Referenced nodes retain their handlers and data in either case. | Changed | Choose the optional jQuery adapter for its documented query and content-operation semantics, not merely to retain referenced nodes during detach. See [`detachContents` policy](/docs/upgrade-guide.md#detachcontents-policy). |
| Radio singleton | Applications commonly consumed the separate `backbone.radio` package, which also backed Marionette's `channelName`, `radioEvents`, and `radioRequests` integration. | Marionette exports its own built-in `Radio` singleton. It does not share channels with `backbone.radio`. | Changed | Replace every `backbone.radio` import together with the Marionette upgrade, including publishers and requesters outside Marionette classes. A mixed migration silently creates two disconnected buses. Do not bridge or mirror them. See [Atomic Radio migration](/docs/upgrade-guide.md#atomic-radio-migration). |
| Multiple Marionette configurations | Root imports and mutable class configuration were effectively process-scoped. | Root imports still form one default runtime. Optional `createMarionette()` calls create isolated runtimes with their own runtime classes, adapters, renderer configuration, and Radio registries. | Added | Keep ordinary root imports unless isolation is required. When using `createMarionette()`, construct Regions and child Applications from the selected runtime. See [Runtime isolation](/docs/runtime-isolation.md). |
| Radio debug configuration | `Radio.DEBUG = true` enabled Backbone.Radio diagnostics. | Use `Radio.setDebug()` and `Radio.setDebug(false)`. The `DEBUG` property is not supported. | Changed | Replace assignments with the explicit method during the atomic Radio migration. |
| Radio request mixin | Backbone.Radio exposed `Radio.Requests` for direct mixin use. | `Requests` is a named export from `@mnjs/radio`; request/reply methods remain on channels and the top-level Radio API. | Changed | Import `Requests` from the Radio package and compose it with `Object.assign({}, Requests)`. |
| Radio diagnostic override hooks | Backbone.Radio exposed `Radio.log` and `Radio.debugLog`. | Both hooks are replaceable on each Radio instance; `setDebug` gates custom warning hooks. | Changed | Assign hooks on the Radio instance your channels use. Hooks receive that Radio as `this` and replacements apply to existing channels. |
| Radio Channel construction and registry | Backbone.Radio exposed its Channel constructor and registry. | `Channel` and `Requests` are named exports from `@mnjs/radio`; each Radio also exposes its Channel constructor. The registry remains private. | Changed | Use `Radio.channel(name)` for shared channels or `new Channel(name)` for independent channels. Standalone owners call `reset()` themselves. |
| Radio method receiver | Backbone.Radio top-level methods read their channel factory and registry from `this`, so borrowed methods could target an alternate receiver. | Top-level methods dispatch through the Radio instance that created them. | Changed | Use `createRadio()` for another registry. Borrowing a method does not create or select another Radio instance. |
| Radio named reset | Resetting an unknown channel could fail with an incidental `TypeError`, and names matching inherited object properties could resolve incorrectly. | `Radio.reset(name)` throws `MN0021` for an unknown channel, while explicitly created channel names are registry-owned. | Changed | Create the channel before resetting it, or call `Radio.reset()` with no arguments to reset all existing channels. |
| Request-name ownership | Inherited request-registry properties could be mistaken for named handlers or the `default` fallback. A `__proto__` request name could change the registry or result-map prototype instead of becoming an own entry. Flattening a nested multi-request result could copy inherited enumerable properties. | Only explicitly registered own handlers are invoked or reported as overwritten. Request result maps use safe own string properties, including for `__proto__`, and nested results contribute own enumerable string properties only. | Changed | Register every named and default handler explicitly; do not depend on request-registry prototype inheritance, and move intended nested result values onto the result object itself. |
| UMD global | Script builds exposed the `Marionette` global. | Unminified and minified UMD compatibility builds remain supported throughout v5 for no-bundler, AMD, and `Marionette`-global consumers. | Preserved | Existing direct-script integrations can retain the global while updating changed APIs. New applications should use the canonical ESM entry. |
| CJS entry | CommonJS consumers could require Marionette. | `require('marionette')` resolves to the CJS compatibility build and returns named API properties throughout v5. | Preserved | Legacy Node and build-tool consumers can destructure the required API instead of expecting a restored default namespace contract. New applications should use ESM. |
| ESM entry | ES module named imports were supported. | `import` resolves to the ESM build and named imports remain supported. ESM is the canonical distribution for new applications. | Preserved | Use named imports from `marionette`. |
| Underscore dependency | Marionette required Underscore through its package dependency relationship. | Marionette core does not import or declare Underscore as a peer dependency. | Removed | Remove Underscore if it was installed only for Marionette; keep it when application code uses it directly. Backbone manages its own dependency. See [Underscore is no longer a peer dependency](/docs/upgrade-guide.md#underscore-is-no-longer-a-peer-dependency). |
| Client ID sequence ownership | Marionette constructors and event-listener bookkeeping drew IDs from Underscore's counter, so external Underscore calls could affect later Marionette numeric suffixes. | One loaded copy of Marionette owns one sequence shared by its constructors and event-listener bookkeeping. Complete Marionette-generated IDs remain unique when types reuse a custom prefix, but the sequence is not coordinated with Underscore or Backbone. | Changed | Treat `cid` values as opaque stable instance identifiers. Do not parse or compare numeric suffixes, depend on allocation order, or coordinate IDs through `_.uniqueId`. |
| Class extension input inheritance | Inherited enumerable properties on the `staticProps` hash passed to `extend` could become child-constructor properties. | The public `protoProps` and `staticProps` hashes contribute own enumerable string and symbol keys. Inherited enumerable statics from the parent constructor remain available on the child. | Changed | Move intended prototype and static definitions onto the corresponding input hash itself; do not inherit configuration into either hash. |
| Instance option and render-data inheritance | Underscore-backed shallow merges could copy inherited enumerable properties when combining constructor options and resolved defaults, Region definitions and defaults, `childViewOptions`, or serialized data and `templateContext`. `mergeOptions` could also read inherited or non-enumerable named properties. | Constructor/default options, Region options, and child View options use own enumerable string and symbol properties and safely preserve a literal own `__proto__` property. `mergeOptions` copies only requested own enumerable string properties. Serialized data and `templateContext` use own enumerable string and symbol properties when both are combined; a one-sided fast path still returns the original object unchanged. | Changed | Move intended merged values onto the supplied object itself; do not use prototype inheritance or non-enumerable properties for these inputs. |
| Target-first root utilities | The package root exported `bindEvents`, `unbindEvents`, `bindRequests`, `unbindRequests`, `mergeOptions`, `getOption`, `normalizeMethods`, and `triggerMethod` wrappers that accepted any compatible target object as their first argument. | These conventions have one canonical form as methods on Marionette instances. The root exports, their internal proxy helper, and the public adapter for applying them to arbitrary plain objects are removed. | Removed | Call the corresponding instance method, such as `owner.normalizeMethods(bindings)` or `owner.bindEvents(entity, bindings)`. When a plain object needs similar behavior, extend `MnObject` or own that local adapter explicitly rather than borrowing a Marionette prototype method. |
| `mergeOptions` key collection | Underscore's iterator accepted strings, `arguments`, generic array-like objects, and ordinary object values as requested option names. Invalid or missing key collections were silently ignored. | `mergeOptions(options, keys)` requires `keys` to be an Array when options are present; the declared contract replaces custom shape validation. | Changed | Pass the requested option names as an Array. |
| Private immediate-child traversal | The private `_getImmediateChildren()` result was passed to Underscore's generic iterator, which also traversed arbitrary keyed objects. | Marionette-owned implementations return Arrays. The private type requires an Array; traversal trusts that contract. | Changed | Do not override private `_getImmediateChildren()`. Use documented View, Region, and CollectionView APIs to own child Views. |
| View constructor option precedence | `View` and `CollectionView` passed options to `preinitialize`, then Backbone assigned the public `model`, `collection`, `el`, `id`, `attributes`, `className`, `tagName`, and `events` options before creating the element. Supplied options therefore won conflicts with assignments made by the hook. | The hook can observe the supplied options before the same public constructor options are reapplied. Conflicting supplied options remain authoritative, while v5's private initialization order is unchanged. | Preserved | Use `preinitialize` to derive early state from constructor options. Use `initialize` when an intentional replacement must occur after final public option assignment and element setup. |
| View `preinitialize` and internal setup order | Before Backbone invoked the host's `preinitialize` hook, `View` installed lifecycle monitoring and constructed Behaviors and Regions; `CollectionView` installed monitoring and constructed its child storage and Behaviors. | The standalone host constructor invokes `preinitialize` before that internal setup. Behavior `initialize` can therefore read host state established by the hook, while the hook cannot depend on constructed Behaviors, Regions, child storage, or lifecycle monitoring. | Changed | Keep early host state derivation in `preinitialize`. Move code that needs Marionette-owned collaborators or lifecycle dispatch to the host's `initialize` method. |
| CollectionView empty Region initialization | The constructor invoked the host's `initialize` before calling overridable `getEmptyRegion()` to establish the default empty-view Region. | The same order is preserved. An override can depend on state established by `initialize`; calling `getEmptyRegion()` from `initialize` remains safe because the later constructor call reuses that Region. | Preserved | Keep empty-Region override setup in `initialize` or `getEmptyRegion`; no migration is required. |
| Destruction during View initialization | A `View` or `CollectionView` destroyed from its own `initialize` continued the constructor tail, rebinding entity events and firing Behavior `initialize` after Behavior destruction. `CollectionView` also replaced its destroyed empty Region with a live one. | Destruction is terminal. After `initialize` returns, a destroying or destroyed host skips remaining constructor setup; a destroyed CollectionView retains its destroyed empty Region. | Changed | Initialization code may destroy a host without adding guards for later constructor setup. Do not expect entity events, Behavior initialization hooks, or a live empty Region after that destruction. |
| Child View collection helpers | `CollectionView#children` proxied Underscore collection methods, including iteratee shorthand, a private-array callback argument, Underscore return values, deep/function-form `invoke`, array-form deep paths in `pluck`, and count coercion. | The 19 documented helpers are owned by Marionette. Callback methods require functions and expose only View and index; `each` returns the child container; `reduce` follows native initial-value rules; `invoke` accepts a direct string method; `pluck` reads one direct View property; positional counts are nonnegative integers. Callback and method shapes are checked by the public types. Invalid counts and an empty reduction without an initial value still throw `MN0024`. | Changed | Replace `map('id')` with `map(view => view.id)` or `pluck('id')`. Replace `pluck(['model', 'cid'])` with `map(view => view.model?.cid)`. Do not use the callback's former third argument or depend on `each` returning an array. Replace deep/function-form `invoke` with an explicit callback, and pass valid integer counts. |
| Child View collection aliases and iteration | Undocumented Underscore aliases such as `forEach`, `detect`, `select`, `all`, `any`, and `include` were available through the proxy. The child container was not natively iterable. | The aliases are removed. The canonical methods remain, and the child container supports `for...of`, spread, destructuring, and `Array.from`. | Changed | Replace the aliases with `each`, `find`, `filter`, `every`, `some`, and `contains`, respectively. Prefer native iteration when no collection-helper return value is needed. |
| Child View identity and ownership | Plain-object cid indexes could mistake inherited property names for children, and `removeChildView` or `detachChildView` could mutate a supplied View that was not actually owned by the CollectionView. | View cids remain Marionette-owned keys. Model identity comes from `DataApi.key()` and is stored in a `Map`; `findByModelCid` is removed while `findByModel` uses the configured adapter. Membership requires the exact View instance. | Changed | Replace `findByModelCid(cid)` with `findByModel(model)`. Configure stable source identity through DataApi rather than adding `cid` to otherwise neutral application data. |
| CollectionView filter iteration | Underscore supplied CollectionView child iteration and predicate-object matching, including accepting arrays as predicate objects. | Function filters run with the CollectionView as their receiver and receive `(childView, index, liveChildArray)` while traversing the initial length densely. Predicate maps snapshot own enumerable string keys and values per pass, require present strictly equal model attributes, and exclude inherited, symbol, and non-enumerable keys. Arrays are not predicate maps. | Changed | Use a function filter for custom matching or mutation-sensitive logic. Supply predicate shorthand as an ordinary object and use the same object reference for nested attribute values that should match. |
| CollectionView removal-only updates | Every collection update flowed through sort, filter, and child rendering, so removing one model could move every surviving child through a document fragment even when default collection ordering or disabled ordering already preserved their relative order. | A removal-only update on an already-rendered, unfiltered CollectionView with default collection ordering or ordering disabled destroys the removed child without moving or rerendering synchronized visible survivors when the default sort, filter, and comparator-query methods are used. Empty-view, deferred-child, custom filter or comparator, overridden query methods, add, and merge cases retain the full update path. | Changed | Observe `remove:child` for removals. Do not rely on sort or `render:children` firing when no surviving child needs sorting, rendering, or placement. Private `_viewComparator` and `_onCollectionUpdate` overrides are not supported extension points; use the documented public options and methods. |
| Event bookkeeping rename | Backbone-compatible private event fields such as `_events`, `_listeningTo`, and `_listenId` could be observed. | Marionette's built-in Events implementation uses private `_rdEvents`, `_rdListeningTo`, `_rdListeners`, and `_rdListenId` fields. | Renamed | Do not read or write event bookkeeping fields; use `on`, `off`, `listenTo`, and `stopListening`. Procedural guidance is tracked in [#147](https://github.com/marionettejs/marionette/issues/147). |
| Event aliases | Backbone.Events exposed `bind` as an alias of `on` and `unbind` as an alias of `off`, including on Radio channels. | Marionette Events and built-in Radio expose only the canonical `on` and `off` methods. The optional Backbone integration does not modify Backbone objects, so native Backbone instances retain `bind` and `unbind`. | Changed | Replace the aliases on Marionette objects and Radio channels. Existing Backbone-owned code may continue using Backbone's native aliases, though `on` and `off` remain preferred. |
| Event and request override dispatch | `once` registered through overridable `on`; `listenToOnce` registered through overridable `listenTo`; and Backbone.Radio registered `replyOnce` through overridable `reply`. Map and space-separated reply operations dispatched each entry through their public method. | The same public override dispatch is preserved. Emitter interoperability calls the documented three-argument `on` and `off` methods once per binding, including when an override delegates with only those documented arguments. | Preserved | Lifecycle and instrumentation mixins may continue overriding the canonical registration methods. Overrides should delegate synchronously when they want the base registration behavior. |
| Object-form event triggering | Backbone.Events treated map keys as event names, ignored the mapped values, and passed arguments after the map to each handler. | Object-form `trigger` is a Marionette extension: each map value is the sole argument for its event, and arguments after the map are not forwarded. | Changed | Move the intended per-event handler argument into each map value. Use separate string-form `trigger` calls when an event needs multiple arguments. |
| Object-form requests | Backbone.Radio passed each mapped value as the first argument to its handler and forwarded arguments after the map. | Marionette preserves that argument order and returns the same per-name result map shape. | Preserved | No request-call change is required. |
| Event-name ownership | Event names matching inherited object properties could fail during registration or consult inherited private-store entries. A literal `__proto__` name could affect the event store's prototype. | Only explicitly registered own event names are dispatched or removed. `constructor`, `toString`, `__proto__`, and other inherited names are ordinary event names, and `__proto__` does not change the store prototype. | Changed | Register and remove event names through `on`, `off`, `listenTo`, and `stopListening`; do not modify or inherit from private event stores. |
| Entity-event map `__proto__` name | Declarative entity-event maps silently discarded an own enumerable `__proto__` name during normalization, so it was never bound or selectively unbound. | `bindEvents` and selective `unbindEvents`, including `modelEvents`, `collectionEvents`, and `radioEvents`, throw `MN0026` before delegation when the map has an own enumerable `__proto__` entry. Marionette does not reject other prototype-collision names: its Events API supports them, but third-party emitters such as Backbone may not safely support every name. | Changed | Rename the `__proto__` entity event or bind it through an entity API that explicitly supports the name; verify other prototype-collision names against the entity's emitter, and omit the map to unbind every event from an entity. |
| `Mn.Object` | The default namespace exposed an `Object` alias for the Marionette object class. | The alias is not restored. | Removed | Use `import { MnObject } from 'marionette';`; final migration guidance is tracked in [#147](https://github.com/marionettejs/marionette/issues/147). |
| `MnObject` | The Marionette object class was available as the named `MnObject` export. | `MnObject` remains a named export. | Preserved | Import it directly: `import { MnObject } from 'marionette';`. |
| Reentrant destruction | Calling `destroy()` from `before:destroy` could recurse or repeat teardown for MnObject, Application, and Region. View guarded reentry, but a throwing `before:destroy` left it unable to retry. | MnObject, View, Behavior, and Region guard repeated synchronous teardown as documented by their class contracts. Application destruction is part of its asynchronous lifecycle: compatible repeated calls share an in-flight Promise, and later calls after destruction resolve `true` without restarting teardown. | Changed | Synchronous lifecycle errors stop teardown; later `destroy()` calls do not retry it. For Application, await `destroy()` and treat a rejected current hook as failure; ordinary supersession resolves rather than rejects. |
| Application lifecycle | `Application#start(options)` synchronously fired `before:start` and `start` on every call and returned the Application. Application had no core stop, restart, readiness, running-state, or overlap contract. | `start`, `stop`, `restart`, and `destroy` return `Promise`. `true` means the requested target state settled, including idempotent no-op; `false` means a later incompatible operation superseded it. Current hook failures reject. `isRunning()` is true only after startup readiness. Readiness hooks receive an operation context whose `signal` is aborted when their phase is invalidated. | Changed | Await startup before route dispatch or other work that requires readiness. Move asynchronous preparation into a Promise returned by `onBeforeStart` and pass its context signal to cancellable work. Do not treat `false` as failure or add a catch for ordinary cancellation. Remove Toolkit-style `triggerStart` / `finallyStart` overrides; core awaits `onBeforeStart` directly. |
| Application ownership and hierarchy | Core Application had no parent, named-child, root, or child lifecycle contract. Toolkit supplied a separate App class with class/config overloads and per-child lifecycle flags. | Application owns existing child Application instances through one explicit registration path. Name, individual-child, presence, and fresh-snapshot reads expose the public ownership contract without private-field access. Owned children start and stop sequentially with their owner. A conflicting direct child operation cancels owner completion, while descendant startup cannot interrupt owner destruction. Parent destruction stops children before its readiness hook, then destroys them in registration order. A child destroyed directly removes itself from its owner. Conflicts throw `MN0031`, while registration after either lifecycle becomes terminal is a no-op. | Added | Keep Toolkit's established `addChildApp`, `getChildApp(s)`, `removeChildApp`, and `getName` vocabulary, but construct the child explicitly and use `hasChildApp` when allocation must be avoided. Remove `AppClass` configs, `preventDestroy`, `*WithParent` flags, and public parent/root traversal; longer-lived capabilities need a longer-lived owner, and children should receive required collaborators explicitly. Await owner and child lifecycle operations. |
| Application root View and Region ownership | Core Application could construct or receive a Region and proxy `showView`, but it read any `currentView` from that Region and did not coordinate Region or root View teardown with Application lifecycle. | The Application's View is its Region's `currentView`, including Views shown directly through the Region. Stop empties the Region's current View. Destroy also destroys a constructed Region, releases a borrowed Region without destroying it, and clears the Region reference. | Changed | Use a Region instance when an external owner controls the host lifetime; use a selector, Region class, or definition object when the Application should own it. Show a new root View from `onStart` after restart. Views shown directly in a borrowed Region are also emptied when the Application stops. |
| Custom `destroy` overrides | An override could mutate owned state before calling the v4 base `destroy()` method. Reentrant calls and throwing `before:destroy` handlers did not have one consistent retry boundary. | The synchronous base method for MnObject, View, CollectionView, Behavior, and Region establishes its destruction guard before `before:destroy`. Application owns a separate asynchronous lifecycle and returns its destroy Promise. Cleanup performed before delegating remains outside either guarantee. | Changed | Audit every custom `destroy` override. Synchronous owner overrides must preserve the base reentry boundary. Application overrides must return or await the Promise from the base operation and must not recreate a synchronous teardown path. |
| Behavior element retargeting | The undocumented `Behavior#proxyViewProperties()` helper copied the host View's element properties onto the Behavior. | Behaviors share their host's fixed root. `Behavior#setElement()` and `proxyViewProperties()` are removed. | Removed | Choose the host root at construction; do not retarget Behaviors independently. |
| Rendering a destroyed View | A destroyed `View#render` could still resolve `getTemplate` before returning, while destroyed `CollectionView#render` behavior was undocumented. | Destroyed View and CollectionView render calls return the same instance without resolving templates, running render lifecycles, changing DOM, or recreating children. No diagnostic is thrown. | Changed | Render only live View and CollectionView instances. |
| Adding a child to a CollectionView during or after destruction | Base `CollectionView#addChildView` could inspect or manage a supplied View and restart rendering once destruction began. | The base method returns the supplied View before inspecting the View, index, or options or changing events, ownership, DOM, or lifecycle state. | Changed | Add the child to a live CollectionView instead. Custom overrides own their behavior unless they delegate to the guarded base method. |
| Delegating entity events during or after View destruction | Base `View#delegateEntityEvents`, `CollectionView#delegateEntityEvents`, and direct delegation through an attached Behavior could resolve maps and bind new model and collection subscriptions once host destruction began. | The base host methods return the host, and direct `Behavior#delegateEntityEvents` returns the Behavior, without resolving maps or binding handlers once the owning View's destruction starts. Behavior reuse after `Behavior#destroy` while its host remains live is outside this contract. `undelegateEntityEvents` is unchanged. | Changed | No guard is needed for a late base host or attached Behavior delegation call. Use a live View or CollectionView when subscriptions must be established, and undelegate before replacing its model or collection. Custom host and Behavior overrides own their behavior unless they delegate to the guarded base method. |
| Binding UI during or after View destruction | Base `View#bindUIElements`, `CollectionView#bindUIElements`, and direct calls through a retained Behavior could query the retained root element and recreate bound UI once host destruction began. | The base host methods return the host, and direct `Behavior#bindUIElements` returns the Behavior, without resolving callable host UI, querying DOM, or binding View or Behavior UI once the owning View's destruction starts. Behavior reuse after `Behavior#destroy` while its host remains live is outside this contract. `unbindUIElements` and the `MN0023` unbound `getUI` diagnostic are unchanged. | Changed | No guard is needed for a late base host or Behavior binding call. Bind only while the owning View or CollectionView is live; continue to unbind explicitly when cleanup is required. Custom host and Behavior overrides own their behavior unless they delegate to the guarded base method. |
| Framework errors | Framework invariant failures exposed names and prose messages without stable machine identifiers. | `MarionetteError` is a named export and framework invariant failures expose stable `MNxxxx` codes. | Changed | Catch `MarionetteError` and branch on `error.code`; do not parse message prose or legacy documentation URLs. |
| Behavior declarations | Underscore could treat non-array values with numeric `length` as array-like behavior lists. | Arrays are the only list form. Object maps use own enumerable string keys in standard order; inherited, symbol, and non-enumerable keys are excluded, and numeric `length` is an ordinary map entry. | Changed | Use an array for list declarations or an ordinary object for named declarations; do not use generic array-like values. |
| UI map ownership | Underscore could treat a UI map with numeric `length` as array-like and skip its other named keys. A literal own `__proto__` key could change the prototype of normalized or bound UI output instead of remaining a UI entry. | UI binding and map-normalization iteration use own enumerable string keys in standard JavaScript own-key order. Numeric `length` is an ordinary key, and literal own `__proto__` remains an own entry without changing output prototypes. Direct `@ui` lookup still accepts any own declared selector key, including a non-enumerable one. Arrays, sparse arrays, and other array-like values are not supported UI maps. | Changed | Supply iterated UI configuration as an ordinary object. Move intended iterated keys onto that object itself; do not use inherited, symbol, or non-enumerable properties or array-shaped maps. |
| `@ui` reference validation | Missing `@ui` keys could normalize to an `undefined` selector or fail incidentally later. | Every `@ui.` reference must name an own, declared `ui` key; otherwise Marionette throws `MN0018` during normalization. | Changed | Define the `ui` key or replace the reference with a literal selector. |
| `getUI` binding lifecycle | Calling `getUI()` without declared or bound UI elements failed with an incidental `TypeError`. | View, CollectionView, and Behavior throw `MN0023` when `getUI()` is called without a declared `ui` map, before binding, or after unbinding. | Changed | Declare a `ui` map, then render a templated View or call `bindUIElements()` explicitly before `getUI()`; bind again before calling it after unbinding. |
| Handler validation | Missing string handlers and invalid non-function values could be silently omitted during delegation or binding. | Every supplied handler must be a function or a string that resolves to a callable method; otherwise Marionette throws `MN0019` before delegation, binding, or selective unbinding. | Changed | Define or remove the named method, supply the handler as a function, or omit the map when unbinding everything. |
| Region declaration maps | Underscore could treat a Region map with numeric `length` as array-like and skip its other named keys. | Region declarations and `addRegions` use own enumerable string keys in standard order. Inherited, symbol, and non-enumerable keys are excluded, and numeric `length` is an ordinary Region name. Arrays and other array-like values are not supported as Region declaration maps. | Changed | Supply Region declarations as an ordinary object and move intended definitions onto that object itself. |
| Region names | Named Region methods inherited JavaScript property-key coercion, so arrays, objects, and Symbols could become or address Region names incidentally. | View Region names are non-empty strings. The public types require strings. Named registration, lookup, removal, and child operations reject empty names with `MN0032`; unsupported shapes have no guaranteed diagnostic. Explicitly registered string collisions such as `constructor`, `toString`, and `__proto__` remain valid. | Changed | Pass the intended non-empty string name directly; do not rely on property-key coercion. |
| Named Region operations | Required View operations could fail with an incidental `TypeError` when the named Region did not exist. | `showChildView`, `detachChildView`, `getChildView`, and `removeRegion` throw `MN0020` for an unknown Region name; `getRegion` and `hasRegion` remain optional lookups. | Changed | Define the Region before using a required operation, or check it with `hasRegion` or `getRegion`. |
| Region presence queries | `View#hasRegion` delegated to overridable `getRegion`, so querying an unrendered View rendered it before checking the name. | `hasRegion` checks only the View's own registered Region names without rendering, dispatching through `getRegion`, or changing View state, DOM, UI bindings, or lifecycle events. Missing and inherited-only names return `false`; prototype-collision names such as `constructor` return `true` when explicitly registered as own Regions. Destroyed Views return `false` after their Regions are removed. | Changed | Use `hasRegion` for a side-effect-free stored-ownership check. Use a child operation when rendering, override dispatch, and resolving the Region element are intended. |
| Region lookup queries | `View#getRegion` rendered an unrendered View before looking up the Region, so `getRegion(name).show(view)` also rendered the parent implicitly. A non-delegating `getRegion` override could bypass that render. | `getRegion` returns an own registered Region without rendering or changing View state, DOM, UI bindings, or lifecycle events. Child operations now render a live, unrendered View before dispatching through overridable `getRegion`, including non-delegating overrides. Destroyed Views return `undefined` after their Regions are removed. | Changed | Use `getRegion` for a side-effect-free optional lookup. Use `showChildView`, `detachChildView`, or `getChildView` to retain deterministic render-before-lookup behavior; render the parent explicitly before calling a selector Region's `show` directly. |
| Region snapshot queries | `View#getRegions` rendered an unrendered View before returning its Region map. | `getRegions` returns a fresh snapshot of own registered Region names without rendering or changing View state, DOM, UI bindings, or lifecycle events. Inherited keys are excluded, own prototype-collision names remain safe own entries, and destroyed Views return an empty snapshot. | Changed | Use `getRegions` for a side-effect-free ownership snapshot. `emptyRegions` remains a mutator: it renders a live, unrendered View before calling overridable `getRegions` and emptying the returned Regions. |
| Region owner and name queries | Region ownership was maintained privately as `_parentView` and `_name`; reusing a Region instance or occupied name could leave conflicting private ownership records. | `Region#getOwner()` and `Region#getName()` expose the one current registered relationship without rendering, resolving elements, allocating a second registry, or mutating ownership. Standalone and successfully destroyed Regions return `undefined`. Re-adding the same Region under its current owner and name is a no-op. Registration rejects different-owner, different-name, lifecycle-state, and occupied-name conflicts with `MN0030` before committing them. If a lifecycle hook creates a conflict during ordered `addRegions` processing, earlier entries remain registered while the conflicting and later entries do not. | Added | Use these methods instead of reading private fields. Remove an existing named Region before replacing it, and use a fresh Region instance for another owner. For render-time setup, declare a stable Region in `regions` and only show its child from `onRender`. Keep `currentView` and `hasView()` for the Region's owned child rather than adding a second child lookup API. |
| Operating through a destroyed Region | `Region#show` could render and retain a new View after destruction, while `empty`, `reset`, and `detachView` could continue mutating View ownership, DOM, or element caches. | After destruction, `show`, `empty`, and `reset` return the Region without changing it; `detachView` returns `undefined`. `show`, `detachView`, and recursive `destroy` calls are also no-ops while destruction is in progress. `empty` and `reset` remain available during cleanup. | Changed | Use a live Region when the operation must occur. Custom overrides own their behavior unless they delegate to the base method. |
| Region destruction timing | `isDestroyed()` became `true` before `reset()` emptied the Region. | `isDestroyed()` becomes `true` after `reset()` completes, before the `destroy` event. It remains `false` in `before:empty` and `empty` handlers invoked during destruction. | Changed | Use the `destroy` event for completed teardown. Keep cleanup overrides synchronous and avoid recursive `empty` or `reset` calls from their own lifecycle handlers. Discard the Region if cleanup throws; later `destroy()` calls do not retry it. |
| `onShow` | `Region` invoked `onShow(region, view, options)` for its `show` lifecycle event. | The Region `show` event and `onShow` method convention remain supported. | Preserved | No lifecycle rename is required. |
| Native DomApi customization | Applications could replace or partially override Marionette's DomApi globally or per class. | The native DomApi is the default and remains customizable with `setDomApi` or class-level setters. | Documented | Customization applies to `View`, `CollectionView`, and `Region`. |
| EventDelegator customization | DOM event delegation was supplied through Backbone view and jQuery behavior. | Native delegation is the default and can be replaced globally with `setEventDelegator` or per class. A complete adapter implements `delegate({ eventName, selector, handler, rootEl })` and returns an idempotent cleanup function for that exact registration; Marionette invokes it at most once. | Changed | Use the [EventDelegator runtime adapter contract](/docs/upgrade-guide.md#eventdelegator-runtime-adapter). Existing registrations retain their original cleanup when configuration changes; the current adapter is selected on the next delegation pass. |
| Failed View construction cleanup | If `initialize()` or later constructor setup threw after DOM events, Behaviors, or State were initialized, those owned resources could remain attached to a caller-owned element or instance graph. | Constructor errors propagate without rolling back partially completed initialization. | Preserved | Do not depend on inspecting or retaining a partially constructed instance after an exception. See the [synchronous failure boundary](/docs/lifecycle.md#synchronous-failures). |
| Host and Behavior DOM declaration collisions | Marionette flattened every Behavior and host `events` and `triggers` map before asking Backbone to delegate it. Identical event-and-selector keys overwrote earlier declarations according to merge order. | The host and each Behavior own independent delegated listeners. Every matching declaration runs once, without an ordering guarantee among Behavior handlers. | Changed | Remove code that depends on one declaration suppressing another. Give handlers distinct selectors or event types when only one should run, or coordinate the shared action explicitly. |
| View DOM event redelegation | `View#delegateEvents(events?)` and `View#undelegateEvents()` refreshed or removed View and Behavior DOM handlers and returned the View. An explicit map replaced the View's configured `events` while retaining triggers and Behavior handlers. `setElement()` dispatched through the public pair. | The public pair remains available on View and CollectionView with the same explicit-map boundary, Behavior and trigger participation, and chainability. Callable maps and current UI selectors are resolved on each delegation pass, existing handlers are removed first, and calls after destruction starts are no-ops. | Preserved | Continue using the pair when declarative DOM configuration changes at runtime. Do not add destroyed-state guards around these calls. A method override owns cleanup or redelegation unless it calls the base method. |
| `View#remove` | View inherited Backbone's `remove()` method, which removed its element and stopped listeners without running Marionette's complete destroy lifecycle. | The inherited method is intentionally removed. | Removed | Use `destroy()` for terminal cleanup. Use an owning Region's `detachView()` when the live View must be retained for reuse. |
| Imperative `View#delegate` and `View#undelegate` | View inherited Backbone's singular low-level helpers for adding and removing individual delegated handlers. | The inherited helpers are intentionally removed; Marionette owns delegation through declarative maps and the EventDelegator adapter. | Removed | Prefer `events` and `triggers`, then call `delegateEvents()` to refresh them. Use native listeners or a custom EventDelegator only for interactions that cannot be expressed declaratively. |
| Delegated DOM event semantics | Backbone delegated View events through jQuery, including jQuery special-event handling, namespaces, `return false` shorthand, and extra arguments supplied through jQuery triggering. | Delegated handlers receive a native event: `currentTarget` remains the View root and Marionette sets `delegateTarget` to the closest matching descendant, invoking once even when multiple ancestors match. Non-bubbling `mouseenter` is not emulated. Namespaces, `return false`, and extra trigger arguments are not native contracts. | Changed | Use bubbling native events or direct listeners, explicit event methods, and `CustomEvent.detail` as appropriate. See [Native delegation versus jQuery events](/docs/upgrade-guide.md#native-delegation-versus-jquery-events). The optional jQuery DomApi does not change event delegation. |
| Adapter overlay input inheritance | DomApi and EventDelegator overlays could contribute inherited enumerable properties. | DomApi overlays copy own enumerable string and symbol properties and preserve a literal own `__proto__` property without changing the adapter prototype. EventDelegator configuration replaces the complete adapter object instead of overlaying it. | Changed | Move intended DomApi overrides onto the supplied object itself. Provide a complete EventDelegator with a callable `delegate` method. |
## Reading changed and removed rows
The highest-impact migration boundaries are:
- update the package name and imports before addressing runtime behavior;
- keep default-namespace and `Mn.Object` compatibility out of new v5 code;
- explicitly opt into Backbone or jQuery compatibility only where an
application still needs it;
- resolve `View` and `CollectionView` selector strings before construction,
while leaving Region selector strings unchanged; and
- audit code that depends on `$el`, jQuery-shaped `view.$()` results, or
the selected adapter's content replacement and cleanup semantics.
The full ordered migration procedure and remaining before-and-after examples are
tracked in issue #147.
### Await Application readiness
V4 startup completed synchronously, so code commonly dispatched work on the
next line:
```javascript
app.start();
dispatchInitialRoute();
```
V5 awaits a Promise returned by `onBeforeStart`. Await `start()` and dispatch
only when that exact startup reaches running state:
```javascript
const App = Application.extend({
onBeforeStart(app, options, { signal }) {
return loadInitialData({ signal });
}
});
const app = new App();
if (await app.start()) {
dispatchInitialRoute();
}
```
A `false` result means a later stop, restart, or destroy superseded this startup.
It is not a failure and does not need a `catch`. A current readiness failure
rejects and should use the application's ordinary error path. Marionette aborts
the readiness signal before replacement readiness starts, so pass it to
cancellable work rather than inventing a parallel cancellation hook.
[Canonical source](/docs/markdown/docs/migration-from-v4.md) · [Source identity](/docs/manifest.json)
---
Document: upgradeGuide.md
Canonical URL: https://marionettejs.com/docs/upgrade-guide/
Markdown URL: https://marionettejs.com/docs/upgrade-guide.md
Reading SHA-256: 00cbeb1cfe92c5af4442ca7b2d45a9747175c760a9f68b64569d987a200141de
# Upgrade guide
## From backbone.marionette.js
See the [v4-to-v5 compatibility ledger](/docs/migration-from-v4.md) for the
current public behavior boundary. Final migration documentation is tracked in
[issue #147](https://github.com/marionettejs/marionette/issues/147).
## Use the included TypeScript declarations
The `marionette` package includes declarations for its public exports in ESM and
CommonJS. Core declarations support TypeScript 6 and 7 with NodeNext or bundler
resolution. Import instance and configuration types from `marionette`; a separate
core type package is not needed. Optional packages keep their own declarations
and compiler support.
Both `.extend()` and direct native subclasses remain available. A native class's
inherited `.extend()` needs an explicit constructor: default forwarding uses
`parent.apply`, which cannot call a native class. Some native overrides after
`.extend()` configuration, especially prototype `options` factories, encounter
TypeScript's distinction between methods and properties. Define those overrides
with `.extend()`, or start the native subclass from the public base.
Custom constructors can replace the instance. Their declared object return is
the constructed type; an unknown return stays unknown. See the
[constructor typing guidance](https://github.com/marionettejs/marionette/blob/b06750c507494441f0b2298766b70087e45346a2/docs/maintainers/types.md) for preserving
the receiver through further extensions and the limits of return annotations.
## Managed children use Marionette's lifecycle
Regions, CollectionView children, and empty Views use Marionette View or
CollectionView instances. Automatic Backbone View lifecycle adaptation is removed,
including `supportsRenderLifecycle`, `supportsDestroyLifecycle`, and the fallback
from `destroy()` to `remove()`.
Wrap an existing non-Marionette view in a Marionette View and own its rendering
and cleanup explicitly. See the [wrapper example](/docs/region.md#wrapping-a-non-marionette-view).
Behaviors also keep their initial host element; their internal `_syncElement()`
retargeting method is removed. Event redelegation still refreshes their handlers.
## Construct Views before showing them
`Region#show` and `View#showChildView` require a Marionette View instance in v5. They no
longer construct a hidden base View from a template function, string, or View-options
object. Make the allocation and ownership explicit:
```js
import { View } from 'marionette';
// v4
parent.showChildView('heading', 'Edit program');
parent.showChildView('content', {
template,
templateContext: { section: 'main' }
});
// v5
parent.showChildView('heading', new View({
template: () => 'Edit program'
}));
parent.showChildView('content', new View({
template,
templateContext: { section: 'main' }
}));
```
## Configure model and collection data
- Marionette core no longer reads Backbone-specific `cid`, `attributes`, `get`,
`models`, `indexOf`, or structural event payloads.
- Plain object models and array collections work through the default DataApi.
- `DataApi.models(collection)` replaces the pre-stable
`DataApi.items(collection)` name without a compatibility alias.
```js
// before
const models = DataApi.items(collection);
// v5
const models = DataApi.models(collection);
```
- View templates with a collection and no model now receive the result of
`serializeCollection()` on the `models` property. By default, that result is an
array of serialized values. Replace the pre-stable `items` property without
retaining both names.
```js
// before
template: ({ items }) => items.map(renderModel)
// v5
template: ({ models }) => models.map(renderModel)
```
- Applications whose Views use Backbone models or collections must select its
DataApi before constructing those Views:
```sh
npm install @mnjs/adapters backbone
```
```js
import BackboneApi from '@mnjs/adapters/backbone';
import { setDataApi } from 'marionette';
setDataApi(BackboneApi);
```
Configure `setStateApi(BackboneApi)` separately only when declarative
`stateEvents` observe a Backbone state source. Using Backbone.Router alone
requires neither adapter. See [Choosing integrations](/docs/choosing-integrations.md).
- Other data sources can configure `setDataApi` with methods for identity,
reads, serialization, ordered model snapshots, subscriptions, and collection
observation. XState actors can use `@mnjs/adapters/xstate`.
See [Data API](/docs/data-api.md).
- State owners return the exact supplied source from `getState()`. Use
`createState(options)` for an owned source, and configure `setStateApi` when
declarative `stateEvents` need observation. The v5 alpha concrete `State`
export is removed. See [State sources and StateApi](/docs/state.md).
- `Application#getParentApp()` and `Application#getRootApp()` are removed. Pass
required collaborators to child Applications explicitly when constructing
them instead of traversing upward.
- Replace `children.findByModelCid(cid)` with `children.findByModel(model)`.
## Native data package
- Use `Model.toObject()` and `Collection.toArray()` for plain attribute data.
`toJSON()` is removed from the native package; serialize those plain values
explicitly with `JSON.stringify`. Template data comes from attributes and is
independent of conversion overrides.
- `Collection.touch()`, `swap()`, and `replace()` are removed. Update an existing
model with `model.set()` and bind child rendering with `modelEvents`. Use
`remove`/`add` or `reset` when replacing membership intentionally.
- `Collection.move(modelOrId, index)` retains existing models and child Views for
explicit list ordering. Listen to `sort`, which both `move` and `sort` emit;
the native `reorder` event is removed.
- Native DataApi keys are model `cid` values, so application ids can change
without changing child identity. Keep application ids unique for unambiguous
collection lookup.
- Collection notifications now follow ordinary synchronous events. They do not
combine nested mutations or recover missed notifications after a listener
throws. Schedule structural mutations requested by collection or child
lifecycle listeners after the current notification has returned.
## CollectionView child rendering
Collection changes, `sort()`, and `filter()` share the child-rendering path.
Existing visible children stay mounted, including with a custom comparator or
filter. `attachHtml` receives only elements that need attaching; it is no longer
called just to reorder mounted children. Reordering uses `Dom.moveEl`.
`Dom.swapEl` is removed; `swapChildViews()` exchanges the children using at most
two `Dom.moveEl` calls. Custom DomApi implementations only need `moveEl` for
these placement operations. The child-render pass restores focus and text
selection if a DOM move loses them; a direct swap only preserves them when the
browser supports state-preserving moves.
Only a numeric `addChildView` index bypasses sorting and filtering. Passing
`null` or options without an index now follows the same comparator/filter path
as omitting the index.
`before:render:children` and `render:children` receive all visible children,
regardless of which templates needed rendering. Do not treat that argument as
an added-children or updated-children list.
Overrides of `sort()` and `filter()` own their behavior. Call the parent method
when you want its sorting, filtering, and rendering steps. The early v5 fallback
that forced a render after an override has been removed.
## CollectionView source order and presentation sorting
- A normalized DataApi `reorder` or `update` keeps keyed children aligned with
the collection source order while `sortWithCollection` is enabled.
- `viewComparator: false` disables the separate presentation comparator; it no
longer freezes the current child order against structural source changes.
- Set `sortWithCollection: false` when a CollectionView must preserve manually
managed child order instead of following the source.
- An immutable update that replaces a model with a different object at the same
stable key recreates that child View. Do not retain references to the old
child across such an update.
## Underscore is no longer a peer dependency
- Marionette v5 core does not import or declare Underscore as a peer dependency.
- Remove an explicit Underscore installation if it existed only for Marionette.
Keep it as an application dependency when your own code uses it, such as an
`_.template` supplied to a View.
- Applications using Backbone still receive Underscore through Backbone's own
declared dependency; the Marionette integration does not import it.
## View roots are fixed at construction
`View#setElement()` and `CollectionView#setElement()` are removed. Choose the
root through `new View({ el })` or `new CollectionView({ el })`; both also accept
an `el` factory. Without an `el`, Marionette creates one from `tagName`.
The public instance `el` is readonly. Direct reassignment is unsupported.
Render into the existing root and use Regions to move or detach the View.
When another system replaces the root, destroy the old View and create a new
owner for the replacement element. Keep persistent state in the model or an
externally owned state source. Custom `setElement()` overrides are no longer
called during construction; move initialization to `initialize()` or an `el`
factory, as appropriate.
## View `el` is element-only
- `View` (and `CollectionView`) accept a DOM element for `el` in v5. Selector
strings are no longer resolved, and jQuery collections must be unwrapped.
- v4 inherited string-`el` resolution from `Backbone.View._ensureElement`, which
used jQuery to look up the selector. v5 drops `Backbone.View` inheritance and
the default jQuery dependency, so the string-resolution path goes with them.
- v5 now throws a `ViewError` with a migration hint on construction when a string is passed, instead of silently storing the raw
string as `view.el` and failing later in DOM code.
- Migration: resolve at the call site.
```js
// v4
new View({ el: '#root' });
// v5
new View({ el: document.querySelector('#root') });
```
- `Region` continues to accept selector strings. That API is Marionette-native
(the Region abstraction has always been "where to mount"), not inherited from
Backbone, so it is preserved. When the mount point is already resolved, pass
its native element rather than a jQuery collection.
## Refresh View root attributes explicitly
Use `renderAttributes()` when `attributes`, `id`, or `className` changed but the
View's template content and owned children should remain in place:
```js
const RowView = View.extend({
attributes() {
return {
'aria-selected': this.selected ? 'true' : 'false'
};
},
className() {
return this.selected ? 'selected' : null;
}
});
row.selected = true;
row.renderAttributes();
```
This explicit refresh is separate from `render()` and emits no render lifecycle
events. With the default DomApi, only explicit `null` removes a named attribute;
`undefined` and omitted keys leave existing attributes untouched. Custom DomApi
adapters must implement the same `setAttributes` behavior.
Attribute maps use DOM attribute names (`class`, `for`), not property names
(`className`, `htmlFor`). The View-level `className` option still works. Earlier
v5 alphas also assigned matching element properties; v5 now applies attributes
only. Update live form values and custom element properties explicitly on `el`.
For boolean HTML attributes, use `disabled: isDisabled ? '' : null` instead of
`disabled: isDisabled`. Other values, including `false`, are converted to strings;
ARIA attributes such as `aria-selected: false` therefore retain `"false"`.
## jQuery DOM compatibility
v5 core does not depend on jQuery and does not create `$el`. Configure the optional
DOM adapter when the application needs jQuery queries and content operations:
```js
import $ from 'jquery';
import { View } from 'marionette';
import JQueryDomApi from '@mnjs/adapters/dom/jquery';
const JQueryView = View.extend({
initialize() { this.$el = $(this.el); }
});
JQueryView.setDomApi(JQueryDomApi);
```
Install `@mnjs/adapters` and `jquery` for this integration. The fixed root
makes the application-owned wrapper valid for the View's lifetime. CollectionViews
and Behaviors can initialize `$el` in the same way. A subclass overriding
`initialize()` must also perform any setup it needs from its application base.
Core View, CollectionView, and Behavior types no longer take a `Wrapped` generic.
`ViewInstance` becomes
`ViewInstance`, and `DomApi` becomes
`DomApi`. Declare `$el: JQuery` on application subclasses
that provide it. Use a TypeScript `declare` field so it does not overwrite the
wrapper initialized by the base constructor.
This integration does not restore Backbone.View inheritance. Resolve selector
strings or unwrap jQuery collections before supplying a View `el`.
## Native delegation versus jQuery events
The default EventDelegator uses `addEventListener` on the View's root element.
During a delegated handler, the native `event.currentTarget` is therefore the
View's root `el`. Marionette sets `event.delegateTarget` to the closest matching
descendant between the original target and that root. If nested ancestors match
the same selector, only that closest match invokes the handler; Marionette does
not invoke it again for every matching ancestor.
This is a native DOM contract, not an emulation of jQuery's event system:
- `mouseenter` does not bubble, and Marionette does not provide jQuery's special
delegated `mouseenter` handling. Use a bubbling event such as `mouseover`
with an appropriate `relatedTarget` check, or bind `mouseenter` directly to
the intended element.
- A name such as `click.menu` is a literal native event type, not a `click`
event in a jQuery namespace. Marionette already tracks and removes a View's
delegated listeners; application-owned native listeners should retain their
own callbacks or abort signals for cleanup.
- Returning `false` from a handler does not prevent the default action or stop
propagation. Call `event.preventDefault()` and/or `event.stopPropagation()`
explicitly.
- Browser `dispatchEvent()` supplies only the event object to a handler; jQuery
trigger arguments are not forwarded. Put application data in a
`CustomEvent`'s `detail`, or use Marionette events when positional arguments
are part of the application contract.
- Delegated `focus` and `blur` handlers run during capture, before listeners on
the target element. A Marionette trigger stops propagation by default, so set
`stopPropagation: false` on a focus or blur trigger when the target must also
receive the event. Marionette does not translate these names to `focusin` or
`focusout`.
The optional jQuery DomApi changes query and DOM-manipulation operations only;
it does not replace the native EventDelegator. Applications with a verified
need for different delegation semantics can provide an explicit adapter through
`setEventDelegator`.
### EventDelegator runtime adapter
An EventDelegator is a complete adapter with one method:
`delegate({ eventName, selector, handler, rootEl })`. It registers that handler
and returns an idempotent cleanup function for the exact registration, including
its original root and listener options. Marionette stores the cleanup and calls
it during redelegation or destruction. Registration and cleanup errors stop the
operation; failed construction is not rolled back. The adapter must not mutate
View internals. See the
EventDelegator Adapter section of the DOM interactions API documentation for
the complete timing, error, and cleanup contract.
## Atomic Radio migration
Marionette v5 owns the `Radio` singleton used by `channelName`, `radioEvents`,
and `radioRequests`. It is not the singleton exported by `backbone.radio`.
Replace every application import in one migration:
```js
// v4
import Radio from 'backbone.radio';
// v5
import { Radio } from 'marionette';
```
This includes publishers and requesters that do not instantiate a Marionette
class. Leaving either import in the application creates two channels with the
same name on disconnected buses, so messages and requests can disappear
without an exception. Do not bridge, mirror, or run both singletons as a
compatibility strategy.
Replace `Radio.DEBUG = true` with `Radio.setDebug()` and disable it with
`Radio.setDebug(false)`. Import the Requests mixin with
`import { Requests } from '@mnjs/radio'` and compose it into an object with
`Object.assign`. Import `Channel` from the same package for standalone channels,
or use `new runtime.Radio.Channel(name)` for runtime-specific logging. Standalone
channels are not registered; their owner calls `reset()` when finished.
`Radio.log` and `Radio.debugLog` remain replaceable hooks, scoped to each Radio
instance. `setDebug(false)` also suppresses custom warning hooks. Existing channels
use replacement hooks immediately, and hooks receive their Radio as `this`.
Request/reply methods are not mixed into `Application`, `Behavior`,
`CollectionView`, `MnObject`, `Region`, or `View` instances. Replace an
alpha-only instance call with an explicit channel:
```js
// before
view.reply('status:current', getStatus);
// v5
Radio.channel('status').reply('status:current', getStatus);
```
Use `radioRequests` on `Application` or `MnObject` for declarative replies on
their configured channel. Any owner can use `bindRequests(channel, bindings)`
when it receives the channel explicitly. Pair that registration with
`unbindRequests(channel)` in the owner's cleanup hook; imperative bindings to an
arbitrary channel are not automatically tracked for destruction. Unbinding this
way removes only that owner's replies.
## `detachContents` policy
- The default native DomApi `detachContents(el)` clears the element via
`el.textContent = ''`. Children are removed from `el`; callers retaining a
child reference still retain its listeners and data.
- v4 used jQuery's `$(el).contents().detach()`, which is jQuery's documented
detach-for-reinsertion path. It removes children from `el` while preserving
jQuery's internal handler/data bookkeeping on those elements.
- Native node removal does not call jQuery's cleanup machinery either.
Referenced detached nodes retain native listeners, jQuery `.on()` handlers,
and `.data()` values with both implementations. Detachment alone is not a
reason to add jQuery. This differs from content replacement with jQuery's
`.html()`, which cleans jQuery handlers and data from removed descendants.
- Applications needing jQuery query and content-operation semantics can select
the optional jQuery DomApi adapter at app boot:
```js
import { setDomApi } from 'marionette';
import JQueryDomApi from '@mnjs/adapters/dom/jquery';
setDomApi(JQueryDomApi);
```
The adapter's `detachContents(el)` calls `$(el).contents().detach()`,
matching the v4 behavior.
- The optional jQuery adapter is described in the
[installation guide](/docs/installation.md#jquery-dom-adapter-is-optional).
### DOM adapter setup
Morphdom and Lit now live under `@mnjs/adapters/dom/` and export DOM
operation objects rather than class installers. Update imports from the former
`render` directory; those package subpaths are removed.
```js
import MorphdomDomApi from '@mnjs/adapters/dom/morphdom';
import LitDomApi from '@mnjs/adapters/dom/lit-html';
MorphView.setDomApi(MorphdomDomApi);
LitView.setDomApi(LitDomApi);
```
Custom renderers must return their template result. `undefined` is passed to
`Dom.setContents` and clears contents with the supplied native, jQuery, Morphdom,
and Lit adapters; it no longer signals a renderer that performed its own DOM
update. Put direct DOM updates in `setContents` instead.
Lit uses element-only `notifyAttach` and `notifyDetach` hooks and no longer patches View
lifecycle methods. Detachment and destruction disconnect directives without
emptying their DOM. With attachment monitoring disabled, deliver these
notifications from application code. Lit event handlers use the element as their
receiver rather than the View; use a closure for View access.
## Shared utilities
Reusable helpers live in `@mnjs/utils`. Core and native data use the same
implementations; install the matching version directly when importing helpers
into your own components. Existing public Marionette helper exports still refer
to those functions. Source-file imports are not package entry points.
Core ESM and CommonJS builds import `@mnjs/utils` and `@mnjs/radio`.
Browser projects loading raw ES modules must map both packages in their import map, or use a
bundler. Standalone UMD builds remain self-contained.
### Native object copying
Use object spread or `Object.assign` instead of the removed `@mnjs/utils`
`assignOwn` and `assignIn` helpers. Configuration copies follow native own-property
semantics, including enumerable symbol keys; string sources expose character keys
instead of being silently ignored. There is no getter-ordering contract beyond
the chosen native operation. `extend` retains inherited enumerable parent statics
and defines subclass properties so they can shadow inherited getters. Dynamic
model and event keys such as `__proto__` remain ordinary data properties.
### Standalone Events, Radio, and data
`@mnjs/utils` owns the shared `Events` implementation. `@mnjs/radio`
exports the default `Radio` and the `createRadio()` factory. Core continues to
export the same Events, Error, and default Radio within each module format.
`createMarionette()` continues to create an isolated Radio for each runtime.
`@mnjs/data` now depends only on utils; core is no longer a peer dependency.
Standalone data and messaging consumers do not need to install Marionette core.
These packages keep the same version and release together with core and adapters.
[Canonical source](/docs/markdown/upgradeGuide.md) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0001
Canonical URL: https://marionettejs.com/errors/MN0001/
Markdown URL: https://marionettejs.com/errors/MN0001.md
Reading SHA-256: 8b884a332790d23a2ca9947db27e4e4ca800690db2d589a44ca31438605d7848
# MN0001: view el must be dom element
Status: retired
Objects: CollectionView, View
Category: dom
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0002
Canonical URL: https://marionettejs.com/errors/MN0002/
Markdown URL: https://marionettejs.com/errors/MN0002.md
Reading SHA-256: 7414f35dfbf770a2809704c5d788ea9c27f72a35f90b290844b94c5e4214a0e7
# MN0002: region el type invalid
Status: retired
Objects: Region
Category: dom
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0003
Canonical URL: https://marionettejs.com/errors/MN0003/
Markdown URL: https://marionettejs.com/errors/MN0003.md
Reading SHA-256: cff081eb2f064d8890ba1dbf2add28adfbde27ad6cbd8e2b07f547bc40efcf13
# MN0003: view already owned
Status: active
Objects: CollectionView, Region, View
Category: ownership
Severity: error
## Remediation
Detach or remove the view from its current Region or CollectionView before showing it elsewhere, or create a new view instance.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0004
Canonical URL: https://marionettejs.com/errors/MN0004/
Markdown URL: https://marionettejs.com/errors/MN0004.md
Reading SHA-256: 7a5f0a0389cbad2c7cea1572dd06149a84f58fdb415712f24b00adea1e84df1a
# MN0004: region el required
Status: active
Objects: Region
Category: dom
Severity: error
## Remediation
Configure the Region with an el selector or DOM element before using it.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0005
Canonical URL: https://marionettejs.com/errors/MN0005/
Markdown URL: https://marionettejs.com/errors/MN0005.md
Reading SHA-256: 3808131e41585745d9aa9b22376f30c02b6d10cb4e01106becbd6f64a1a58584
# MN0005: region el not found
Status: active
Objects: Region
Category: dom
Severity: error
## Remediation
Render the parent View before direct selector-backed Region operations, ensure the selector resolves within its parent element, or explicitly allow a missing element where supported.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0006
Canonical URL: https://marionettejs.com/errors/MN0006/
Markdown URL: https://marionettejs.com/errors/MN0006.md
Reading SHA-256: b18d4b965ed0f2d17ed604f3c0bf6b43125691c1a314c618de0b66b417e21d2f
# MN0006: region view required
Status: retired
Objects: Region
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0007
Canonical URL: https://marionettejs.com/errors/MN0007/
Markdown URL: https://marionettejs.com/errors/MN0007.md
Reading SHA-256: 04972e5527754b44a3aa71001a6ee8d7188eca5635e17ba747571004588fdbcd
# MN0007: region view destroyed
Status: active
Objects: Region, View
Category: lifecycle
Severity: error
## Remediation
Create a new View instance instead of attempting to show a destroyed view.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0008
Canonical URL: https://marionettejs.com/errors/MN0008/
Markdown URL: https://marionettejs.com/errors/MN0008.md
Reading SHA-256: 8fbfb8f6471f15a5da7f16c055656b784ef440e994483b86aad9a27ec42f3a60
# MN0008: region definition invalid
Status: retired
Objects: Application, Region, View
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0009
Canonical URL: https://marionettejs.com/errors/MN0009/
Markdown URL: https://marionettejs.com/errors/MN0009.md
Reading SHA-256: d584d785cd1beef5b2c4697906506ab0000f1a8c40a67d61dacdff59b086d1c1
# MN0009: event bindings invalid
Status: retired
Objects: Application, Behavior, CollectionView, MnObject, Region, View
Category: communication
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0010
Canonical URL: https://marionettejs.com/errors/MN0010/
Markdown URL: https://marionettejs.com/errors/MN0010.md
Reading SHA-256: 30136b709d90ea4a6e762f9090469017b8bcd6799062312bc271bb713dddb107
# MN0010: request bindings invalid
Status: retired
Objects: Application, Behavior, CollectionView, MnObject, Region, View
Category: communication
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0011
Canonical URL: https://marionettejs.com/errors/MN0011/
Markdown URL: https://marionettejs.com/errors/MN0011.md
Reading SHA-256: 777ded415378998f276f7a7eac30fb679907188e08f57a1ba7a83600133c6126
# MN0011: collection view child view required
Status: active
Objects: CollectionView
Category: configuration
Severity: error
## Remediation
Configure childView with a View class or a function that returns a View class.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0012
Canonical URL: https://marionettejs.com/errors/MN0012/
Markdown URL: https://marionettejs.com/errors/MN0012.md
Reading SHA-256: f9997c022e1d503a9df5debd955becbc82876f68a0ae9fda4d6bb188ca6e4811
# MN0012: collection view child view invalid
Status: retired
Objects: CollectionView
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0013
Canonical URL: https://marionettejs.com/errors/MN0013/
Markdown URL: https://marionettejs.com/errors/MN0013.md
Reading SHA-256: 3c32e8ea72b25150390f9ec20be0052b0b94cf4c7df1efbfbd98968bd5f2d125
# MN0013: collection view container not found
Status: active
Objects: CollectionView
Category: dom
Severity: error
## Remediation
Ensure childViewContainer resolves to an element within the rendered CollectionView.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0014
Canonical URL: https://marionettejs.com/errors/MN0014/
Markdown URL: https://marionettejs.com/errors/MN0014.md
Reading SHA-256: f3ef961d575cb45e25888b11b456cf9aa1a3776a8e49cb899e73b0d28b92a2c1
# MN0014: collection view filter invalid
Status: retired
Objects: CollectionView
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0015
Canonical URL: https://marionettejs.com/errors/MN0015/
Markdown URL: https://marionettejs.com/errors/MN0015.md
Reading SHA-256: 972be450f3de0a0a30aec3e33cdd914c47b9d0d9777948706a2453ca05920820
# MN0015: collection view swap non children
Status: active
Objects: CollectionView
Category: ownership
Severity: error
## Remediation
Pass two views currently owned by the CollectionView to swapChildViews.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0016
Canonical URL: https://marionettejs.com/errors/MN0016/
Markdown URL: https://marionettejs.com/errors/MN0016.md
Reading SHA-256: e2a5811f4e6c418cb4874a6e576d040d7e4b5aa167ba997c5dcc6c23f8343f21
# MN0016: behavior definition invalid
Status: retired
Objects: Behavior, CollectionView, View
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0017
Canonical URL: https://marionettejs.com/errors/MN0017/
Markdown URL: https://marionettejs.com/errors/MN0017.md
Reading SHA-256: 9a6d76979e2852833daee4dee719ee3f8c180dbe83495c805f7aa891d1a77d17
# MN0017: radio channel name required
Status: active
Objects: Radio
Category: communication
Severity: error
## Remediation
Pass a non-empty channel name when creating or accessing a Radio channel.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0018
Canonical URL: https://marionettejs.com/errors/MN0018/
Markdown URL: https://marionettejs.com/errors/MN0018.md
Reading SHA-256: a2a752ad787afc3b9cac901a9348097634c0a18882b6cb7f1968a055ec75e946
# MN0018: ui reference invalid
Status: active
Objects: Behavior, CollectionView, View
Category: configuration
Severity: error
## Remediation
Use @ui. with a non-empty own key whose value is a string selector, or replace the reference with a literal selector.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0019
Canonical URL: https://marionettejs.com/errors/MN0019/
Markdown URL: https://marionettejs.com/errors/MN0019.md
Reading SHA-256: d5142f998935339dfd8f09f5115ad43e10d6adbf0dafa44742f534d04dc740a8
# MN0019: handler not callable
Status: active
Objects: Application, Behavior, CollectionView, MnObject, Region, View
Category: communication
Severity: error
## Remediation
Provide a function or the string name of a callable method on the binding context.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0020
Canonical URL: https://marionettejs.com/errors/MN0020/
Markdown URL: https://marionettejs.com/errors/MN0020.md
Reading SHA-256: 57a621e9c15427179f461a5e0b7c168355e5944cbe2f23e633a30dfc21f8cfaf
# MN0020: named region not found
Status: active
Objects: View
Category: configuration
Severity: error
## Remediation
Define the named Region before using child-View or Region-removal operations, or use getRegion or hasRegion for optional lookup.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0021
Canonical URL: https://marionettejs.com/errors/MN0021/
Markdown URL: https://marionettejs.com/errors/MN0021.md
Reading SHA-256: bd7727d567d1f0af9efc179582c73765fdc0d5d16f4a1e5ed1aa00a973c0cd0d
# MN0021: radio channel not found
Status: active
Objects: Radio
Category: communication
Severity: error
## Remediation
Create the named channel with Radio.channel(name) before resetting it, or call Radio.reset() with no arguments to reset all existing channels.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0022
Canonical URL: https://marionettejs.com/errors/MN0022/
Markdown URL: https://marionettejs.com/errors/MN0022.md
Reading SHA-256: e3d7711cb115fbe3de335e0c81f8e71d59e1e261ecdc5f1bd6e80de9e80159b5
# MN0022: collection view empty view invalid
Status: retired
Objects: CollectionView
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0023
Canonical URL: https://marionettejs.com/errors/MN0023/
Markdown URL: https://marionettejs.com/errors/MN0023.md
Reading SHA-256: f2abdd262d39f2c538bd0f80e1b713057221eeeb5a5e47ccb56aa1a002baec04
# MN0023: ui elements unavailable
Status: active
Objects: Behavior, CollectionView, View
Category: lifecycle
Severity: error
## Remediation
Declare a ui map, then render the View or explicitly bind its UI elements before calling getUI; bind them again before calling getUI after unbinding.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0024
Canonical URL: https://marionettejs.com/errors/MN0024/
Markdown URL: https://marionettejs.com/errors/MN0024.md
Reading SHA-256: cd1a41e24402d7f82eab71ccb297220a296f562afa48db3eb7e0873dca65050a
# MN0024: child container argument invalid
Status: active
Objects: CollectionView
Category: configuration
Severity: error
## Remediation
Pass nonnegative integer counts. Reducing an empty child container requires an initial value.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0025
Canonical URL: https://marionettejs.com/errors/MN0025/
Markdown URL: https://marionettejs.com/errors/MN0025.md
Reading SHA-256: d3d10535d2134bee64f3ef1d11a78ccb9752d622edc08ff67eacaacb1fb67f37
# MN0025: child container method not callable
Status: retired
Objects: CollectionView
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0026
Canonical URL: https://marionettejs.com/errors/MN0026/
Markdown URL: https://marionettejs.com/errors/MN0026.md
Reading SHA-256: efd8ec7e7f97ef0e88be75ef41d5f07e965b7c5d2002e9573b598d57777e696b
# MN0026: entity event name unsafe
Status: active
Objects: Application, Behavior, CollectionView, MnObject, Region, View
Category: communication
Severity: error
## Remediation
Rename an own __proto__ entry in an entity-event map before binding or selectively unbinding it.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0027
Canonical URL: https://marionettejs.com/errors/MN0027/
Markdown URL: https://marionettejs.com/errors/MN0027.md
Reading SHA-256: 7ee72950da25fc65cb3fc2f2e14571c2efc485461e77e2ee6104ea224c2ea5e1
# MN0027: feature name invalid
Status: retired
Objects: Behavior, CollectionView, View
Category: configuration
Severity: error
## Remediation
The v5 feature registry is removed. Configure child event prefixes per View, trigger behavior per trigger, and application values through State or explicit configuration.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0028
Canonical URL: https://marionettejs.com/errors/MN0028/
Markdown URL: https://marionettejs.com/errors/MN0028.md
Reading SHA-256: d1f1c5354fe123e9f31c0cd086c60a3364d80ec7385b916a09b8b4068a8ad760
# MN0028: region destroyed operation
Status: retired
Objects: Region
Category: lifecycle
Severity: error
## Remediation
Calls to show, empty, or reset after Region destruction are lifecycle-safe no-ops. Use a live Region when the operation must take effect.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0029
Canonical URL: https://marionettejs.com/errors/MN0029/
Markdown URL: https://marionettejs.com/errors/MN0029.md
Reading SHA-256: 619151985ce25aee4a135a8b7fcc50c8558de8dd928c8644f6e55d6aa2efe99b
# MN0029: view destroyed set element
Status: retired
Objects: CollectionView, View
Category: lifecycle
Severity: error
## Remediation
Calls to setElement after View or CollectionView destruction begins are lifecycle-safe no-ops. Use a live instance when element replacement must take effect.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0030
Canonical URL: https://marionettejs.com/errors/MN0030/
Markdown URL: https://marionettejs.com/errors/MN0030.md
Reading SHA-256: dd3339073a8895dfcfc482366670d27d3f0b4d6785c58c0714b82ea45a3c7bcd
# MN0030: region registration conflict
Status: active
Objects: Region, View
Category: ownership
Severity: error
## Remediation
Register a live, unowned Region under an unused name; remove an existing named Region before replacing it and use a fresh Region instance for a different owner.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0031
Canonical URL: https://marionettejs.com/errors/MN0031/
Markdown URL: https://marionettejs.com/errors/MN0031.md
Reading SHA-256: dcbfdc1c34fbdb9594182c85bf8b80d890da863158406bb559f7a9b89fbec8bf
# MN0031: application registration conflict
Status: active
Objects: Application
Category: ownership
Severity: error
## Remediation
Register a live, unowned Application instance under an unused non-empty string name; use hasChildApp before constructing a dynamic child when allocation must be avoided.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0032
Canonical URL: https://marionettejs.com/errors/MN0032/
Markdown URL: https://marionettejs.com/errors/MN0032.md
Reading SHA-256: 677781cf631fd60c192965e10a41f08e419ca6df1e5f82730c080fb39b271931
# MN0032: region name invalid
Status: active
Objects: View
Category: ownership
Severity: error
## Remediation
Pass a non-empty string name to a named Region operation.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0033
Canonical URL: https://marionettejs.com/errors/MN0033/
Markdown URL: https://marionettejs.com/errors/MN0033.md
Reading SHA-256: dd23595f7ace41f75ed90f02312f29a8fcb1fc942e77672c5ee6f20c5155f94c
# MN0033: merge options keys invalid
Status: retired
Objects: Application, Behavior, CollectionView, MnObject, Region, View
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0034
Canonical URL: https://marionettejs.com/errors/MN0034/
Markdown URL: https://marionettejs.com/errors/MN0034.md
Reading SHA-256: a7cad34a588c69fd2e1e082310a7b8571891b31abec06009e034f2fa9de90f40
# MN0034: state key invalid
Status: retired
Objects: StateApi
Category: configuration
Severity: error
## Remediation
The concrete v5 alpha State key validation is removed. Use the selected source's native key contract.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0035
Canonical URL: https://marionettejs.com/errors/MN0035/
Markdown URL: https://marionettejs.com/errors/MN0035.md
Reading SHA-256: 97f7c4a427ef5572b99cc65ed904e7a39261389dbf2bb503361ff1648388d63c
# MN0035: state ownership conflict
Status: retired
Objects: Behavior, CollectionView, MnObject, View
Category: ownership
Severity: error
## Remediation
The concrete v5 alpha State ownership rule is removed. Supplied sources are borrowed and may be shared by multiple owners; createState results are owned and disposed by their owner.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0036
Canonical URL: https://marionettejs.com/errors/MN0036/
Markdown URL: https://marionettejs.com/errors/MN0036.md
Reading SHA-256: 53b7deb4f31876430d9c8ff04fcc744d1496897ce0be96e8d00cbe0588955e3e
# MN0036: event delegator contract invalid
Status: retired
Objects: Behavior, CollectionView, View
Category: configuration
Severity: error
## Remediation
Use the documented argument types. Marionette no longer emits a dedicated runtime diagnostic for this unsupported input shape.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0037
Canonical URL: https://marionettejs.com/errors/MN0037/
Markdown URL: https://marionettejs.com/errors/MN0037.md
Reading SHA-256: 10c30f6d32962e0606cbc62331c7f70c346e44bd1177c1517c5603eddb744752
# MN0037: adapter observation unsupported
Status: active
Objects: Application, Behavior, CollectionView, MnObject, View
Category: configuration
Severity: error
## Remediation
Configure a StateApi or DataApi that can observe the selected source, or remove the declarative event map.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0038
Canonical URL: https://marionettejs.com/errors/MN0038/
Markdown URL: https://marionettejs.com/errors/MN0038.md
Reading SHA-256: 3042b84a37efe4dba22f70d2831b7b3e630c4aceb16a48a147741bdc6be83786
# MN0038: adapter cleanup invalid
Status: retired
Objects: Application, Behavior, CollectionView, MnObject, View
Category: configuration
Severity: error
## Remediation
DataApi and StateApi adapters must return cleanup functions. Core no longer wraps or validates cleanup on each registration.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/MN0039
Canonical URL: https://marionettejs.com/errors/MN0039/
Markdown URL: https://marionettejs.com/errors/MN0039.md
Reading SHA-256: 9d5d87c884052f20a0213ea7b27d3a3f2c891826337f82ab4941ae4e1bbc45d6
# MN0039: collection data contract invalid
Status: active
Objects: CollectionView
Category: configuration
Severity: error
## Remediation
Return an ordered array with unique stable keys and emit a valid reorder, reset, or update structural record.
[Diagnostic catalog](/errors/index.md) · [Source identity](/docs/manifest.json)
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)
---
Document: errors/index
Canonical URL: https://marionettejs.com/errors/
Markdown URL: https://marionettejs.com/errors/index.md
Reading SHA-256: 6ed6699baacdaa830950596305c8e41b4b15d62a6aac7a180e50abb15a5abd4a
# Diagnostic codes
- [MN0001: view el must be dom element](/errors/MN0001.md): retired
- [MN0002: region el type invalid](/errors/MN0002.md): retired
- [MN0003: view already owned](/errors/MN0003.md): active
- [MN0004: region el required](/errors/MN0004.md): active
- [MN0005: region el not found](/errors/MN0005.md): active
- [MN0006: region view required](/errors/MN0006.md): retired
- [MN0007: region view destroyed](/errors/MN0007.md): active
- [MN0008: region definition invalid](/errors/MN0008.md): retired
- [MN0009: event bindings invalid](/errors/MN0009.md): retired
- [MN0010: request bindings invalid](/errors/MN0010.md): retired
- [MN0011: collection view child view required](/errors/MN0011.md): active
- [MN0012: collection view child view invalid](/errors/MN0012.md): retired
- [MN0013: collection view container not found](/errors/MN0013.md): active
- [MN0014: collection view filter invalid](/errors/MN0014.md): retired
- [MN0015: collection view swap non children](/errors/MN0015.md): active
- [MN0016: behavior definition invalid](/errors/MN0016.md): retired
- [MN0017: radio channel name required](/errors/MN0017.md): active
- [MN0018: ui reference invalid](/errors/MN0018.md): active
- [MN0019: handler not callable](/errors/MN0019.md): active
- [MN0020: named region not found](/errors/MN0020.md): active
- [MN0021: radio channel not found](/errors/MN0021.md): active
- [MN0022: collection view empty view invalid](/errors/MN0022.md): retired
- [MN0023: ui elements unavailable](/errors/MN0023.md): active
- [MN0024: child container argument invalid](/errors/MN0024.md): active
- [MN0025: child container method not callable](/errors/MN0025.md): retired
- [MN0026: entity event name unsafe](/errors/MN0026.md): active
- [MN0027: feature name invalid](/errors/MN0027.md): retired
- [MN0028: region destroyed operation](/errors/MN0028.md): retired
- [MN0029: view destroyed set element](/errors/MN0029.md): retired
- [MN0030: region registration conflict](/errors/MN0030.md): active
- [MN0031: application registration conflict](/errors/MN0031.md): active
- [MN0032: region name invalid](/errors/MN0032.md): active
- [MN0033: merge options keys invalid](/errors/MN0033.md): retired
- [MN0034: state key invalid](/errors/MN0034.md): retired
- [MN0035: state ownership conflict](/errors/MN0035.md): retired
- [MN0036: event delegator contract invalid](/errors/MN0036.md): retired
- [MN0037: adapter observation unsupported](/errors/MN0037.md): active
- [MN0038: adapter cleanup invalid](/errors/MN0038.md): retired
- [MN0039: collection data contract invalid](/errors/MN0039.md): active
[Canonical source](/docs/markdown/config/diagnostics/catalog.json) · [Source identity](/docs/manifest.json)