5.0.0-beta.1 · Published beta · b06750c5. Published on npm. Match your installed version.
ConsumerView Lifecycle#
Both View and CollectionView are aware of their lifecycle state
which indicates whether the View is rendered, attached, or destroyed.
Documentation Index#
- View Lifecycle
- Lifecycle State Methods
- Instantiating a View
- Rendering a View
- Rendering Children
- Attaching a View
- Detaching a View
- Destroying a View
- Synchronous failures
- Destroying Children
Lifecycle State Methods#
Both View and CollectionView share methods for checking lifecycle state.
isRendered()#
Returns a boolean value reflecting if the view is considered rendered.
isAttached()#
Returns a boolean value reflecting if the view is considered attached to the DOM.
isDestroyed()#
Returns a boolean value reflecting if the view has been destroyed.
State vectors#
The three lifecycle methods are independent observations, not one linear state enum.
View construction can therefore produce any of the four alive render/attachment vectors:
Initial el |
isRendered() |
isAttached() |
isDestroyed() |
|---|---|---|---|
| Empty and detached | false |
false |
false |
| Empty and in the document | false |
true |
false |
| Populated and detached | true |
false |
false |
| Populated and in the document | true |
true |
false |
CollectionView starts unrendered regardless of its initial contents and has its own
lifecycle transition table.
With lifecycle monitoring enabled, Marionette-managed operations preserve the following observable transitions:
| Operation | Result | Repeated call |
|---|---|---|
View#render() with a template function while alive |
Runs before:render and render; rendered becomes true; attachment is unchanged |
Renders again and runs the render lifecycle again |
View#render() with template: false while alive |
Returns the View without running the render lifecycle or changing contents or state | Repeated calls are the same no-op |
CollectionView#render() while alive |
Runs before:render and render, rebuilds its children, and becomes rendered; attachment is unchanged |
Rebuilds the children and runs the render lifecycle again |
view.renderAttributes() while alive |
Applies the current root attribute declarations without changing contents, children, lifecycle events, or state | Reevaluates and applies the declarations again |
region.show(view) |
Ensures the view is rendered; attached becomes true only when the Region is in the document |
Showing the current view is a no-op |
region.detachView() |
Rendered is preserved; attached becomes false; destroyed stays false |
Returns undefined with no transition |
| Re-show a detached view | Rendered stays true; attachment reflects the Region |
Does not render the view again |
region.empty() or view.destroy() |
Rendered and attached become false; destroyed becomes true |
Repeated destroy is a no-op |
view.render() after destruction |
Returns the same View with rendered and attached false and destroyed true |
Repeated calls are no-ops |
view.renderAttributes() once destruction begins |
Returns the same View before resolving declarations or changing the root element or lifecycle state | Repeated calls are no-ops |
CollectionView#addChildView(view, ...) once destruction begins |
Returns the supplied child before inspecting or taking ownership of it; the caller remains responsible for that child | Repeated calls are no-ops for the destroyed CollectionView |
view.delegateEvents() or view.undelegateEvents() once destruction begins |
Returns the same View without changing View or Behavior DOM delegation | Repeated calls are no-ops |
view.bindUIElements() once destruction begins |
Returns the same View without resolving host UI, querying DOM, or binding View or Behavior UI | Repeated calls are no-ops |
Setting monitorViewEvents: false on a Region's owning view intentionally disables
attachment events and automatic isAttached() updates for the shown view.
This table specifies the managed and terminal operations listed above. Do not infer behavior for other calls on a destroyed View; custom overrides also own their behavior unless they delegate to a guarded base method.
Instantiating a View#
Every Marionette View and CollectionView has a native DOM element in el.
Pass an existing element with el: document.querySelector('.foo-selector'), or
create one first with document.createElement(). Selector strings and jQuery
collections are not valid View el values.
When el is omitted, Marionette creates the root element from tagName (a
div by default) and applies the resolved id, className, and attributes.
The element remains the View's root for its entire lifetime. Native core does not create $el;
applications can initialize their own wrapper when using the
jQuery adapter.
Marionette determines whether the initial root is already rendered or attached. If a View starts rendered or attached, its state reflects that status, but the related events will not have fired. An element owned by template content is detached while that owner document has no document element. Showing its View later through an attached Region runs the managed attachment lifecycle once for the View and its existing children.
For more information on instantiating a view with pre-rendered DOM, see Pre-rendered Content.
A fixed root element#
Choose the root with the constructor's el option, or let Marionette create it.
A View and its Behaviors keep that element for their lifetime. el is readonly
in the public instance types; assigning another element directly is unsupported.
There is no public setElement() method.
Rendering changes the root's contents. Moving or detaching a View through a Region preserves its root and its child ownership. If another system replaces the root, destroy the old View and construct a new View with the new element. Keep state that must survive that replacement outside the View.
Rendering a View#
In Marionette rendering a view is changing a view's el's contents.
What rendering indicates varies slightly between the two Marionette views.
Note A completed render leaves the View rendered until destruction. During a normalized collection update, CollectionView may mark an updated child unrendered before rendering it again; a filtered child can remain unrendered until it becomes visible.
View Rendering#
For View, rendering with a template function runs the
before:render lifecycle, serializes the View's data, passes it to the template,
places the result in el, binds UI, marks the View rendered, and then runs the
render lifecycle. A newly constructed View is already considered rendered if
its initial el contains content. A later template may produce empty content;
the completed render still leaves the View rendered.
template: false is different from a template that returns an empty value.
Calling View#render() with template: false returns the View without running
the render lifecycle, changing the DOM, or changing its rendered state.
CollectionView Rendering#
For CollectionView, every live render() is
bracketed by before:render and render. After it completes, collection-backed
children have been rebuilt, the optional template and visible children have
been rendered, and the CollectionView is rendered. Any children the
CollectionView owned before that render have been destroyed.
Inserting a child element into the CollectionView is not itself an attachment transition. When the CollectionView is monitored as attached, rendering marks and notifies the inserted children as attached; when the parent is detached or child lifecycle monitoring is disabled, their monitored attachment state remains detached even though their elements are inside the parent element.
A CollectionView with no children is still rendered, with or without an
emptyView. Its own
template controls the container markup but does not determine rendered state.
Rendering Children#
Rendering child views is often best accomplished after the View renders, as the first render typically happens before the View enters the DOM. This helps to prevent unnecessary repaints and reflows by making the DOM insertion at the highest practical View in the view tree.
The exception is Views with pre-rendered content. When a View is instantiated
rendered, child Views are best managed in the View's initialize.
View Children#
In general the best method for adding a child view to a View is to use showChildView
in the render event.
View Regions are emptied on each render, so Views shown outside of the render event still need to be shown again
on subsequent renders.
CollectionView Children#
The primary use case for a CollectionView is maintaining collection-backed
child Views. Marionette creates and removes those children as the collection
changes.
addChildView() can also add a child that is independent of the collection,
but that child is not unmanaged. The CollectionView owns it, includes it in its
child containers, and may sort or filter it. Rendering, collection reset, or
CollectionView destruction destroys every child that is still owned, including
manually added children. detachChildView() is the explicit operation that
removes a child from ownership without destroying it and transfers cleanup
responsibility to the caller.
See Self-Managed children
for the supported add, remove, detach, sorting, and filtering contracts.
Attaching a View#
isAttached() is Marionette's monitored lifecycle state, not a live query of
the physical DOM on every call. Construction initializes it
from the current root element, and Marionette-managed Region and CollectionView
operations update it while attachment monitoring is enabled.
The attach event is the
appropriate place to add listeners to the root el. Render can replace the
contents while that root remains attached; use
dom:refresh for listeners tied to those
rendered descendants.
Moving view.el directly with native DOM APIs, such as
document.body.append(view.el), changes its physical location without running
Marionette attachment lifecycles or updating isAttached(). The same caveat
applies when application code directly removes or moves an attached root.
Prefer a Region or CollectionView for managed transitions; if application code
moves the element directly, it owns the resulting lifecycle mismatch.
A child shown in a rendered but detached parent View's Region is rendered and remains
detached. When the parent is later shown in an attached Region, attachment propagates
to its existing children. A child shown during the parent's onAttach is attached
immediately. Showing the same attached parent again is a no-op for both parent and child
attachment lifecycles.
Detaching a View#
A managed View becomes detached when Marionette removes its el from the DOM
and updates its monitored attachment state.
Use the before:detach event
to clean up listeners added to the root el. Render can replace descendants
while the root remains attached; use
dom:remove to clean up listeners tied to
those rendered descendants.
Detaching a parent View propagates detachment to its managed Region children while preserving their rendered state and ownership. Re-showing that parent attaches the same children again. Emptying the parent-owning Region then detaches and destroys the parent and its still-managed children once.
Destroying a View#
Destroying a View (for example, myView.destroy()) removes Marionette-owned
resources: delegated View and Behavior DOM handlers, bound UI, outgoing
listenTo() subscriptions, entity-event bookkeeping, Behaviors, Regions and
their current Views, and CollectionView children that remain owned. It detaches
the root element and leaves the View rendered false, attached false, and
destroyed true after successful teardown.
Destroy does not remove callbacks registered directly on the View with on(),
destroy its model, collection, or arbitrary option collaborators, or clean up
application resources Marionette does not own. Release those resources in the
appropriate lifecycle callback.
The before:destroy event is the best place to clean
up any added listeners not related to the view's DOM.
Once destruction begins, reentrant destroy() calls from before:destroy or
destroy, and later repeated calls, return the same View without restarting
teardown. During a normal successful teardown, an attached parent and its owned
children complete their detach and destroy lifecycles once.
Base View#bindUIElements() and CollectionView#bindUIElements() calls are
also terminal no-ops once destruction begins. They do not resolve callable UI,
query the retained root element, or bind attached Behaviors. A direct
Behavior#bindUIElements() call through a Behavior owned by or retained from
that host returns the Behavior without binding. unbindUIElements() remains
available for cleanup, and getUI() continues to throw MN0023 when UI is
unbound.
Errors from lifecycle handlers propagate and stop the operation, as described
under Synchronous failures. A throwing before:destroy
or later cleanup handler does not clear the destruction guard or make a later
destroy() call resume teardown.
Successful destruction retains the root el object but detaches it. Do not
infer that all of its contents are retained: owned child Views are removed as
they are destroyed, and Region or CollectionView cleanup can detach contents
from managed containers. Marionette makes no general cleanup promise for
unowned DOM outside those managed boundaries.
Synchronous failures#
Marionette expects valid adapters and working registration and cleanup callbacks. An exception during synchronous registration, construction, rendering, or teardown propagates to the caller and aborts that operation. Completed work is not rolled back. Marionette does not promise to release every resource after a callback throws, restore a partially initialized or rendered instance, or recover on the next call or source notification. Fix the failing callback or adapter; do not rely on partial instance state after a failure.
Successful cleanup and the documented ownership and repeated-destruction rules still apply. A callback that destroys or mutates an owner during an in-progress render does not acquire additional recovery guarantees merely because it calls a public method; use the documented lifecycle boundaries for that workflow.
Application's asynchronous lifecycle has its own readiness, cancellation, rejection, and restart semantics. This synchronous failure boundary does not replace those contracts or change ordinary supersession into an error.
Destroying Children#
Children still owned by a View's Region or a CollectionView are automatically
destroyed when their owner completes a re-render or is destroyed. A CollectionView also
destroys its currently owned children when its collection is reset before
building the replacement collection-backed children. A child returned by
detachView() or detachChildView() is no longer owned and is not included in
later owner cleanup.
During owner destruction, children are removed after the parent root is detached to avoid repeated reflows or repaints.