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

# Marionette.CollectionView

A `CollectionView` manages repeated parts of a screen: rows, cards, or any
ordered set of child views within a root element, `el`. It creates children
from a `collection`, or lets you add and remove child views yourself.

Plain arrays work with the default [Data API](/docs/data-api.md). Use an adapter
when your collection needs to notify the view about changes; mutating a plain
array does not send those notifications.

`CollectionView` includes:
- [The DOM API](/docs/dom-api.md)
- [Class Events](/docs/class-events.md#collectionview-events)
- [DOM Interactions](/docs/dom-interactions.md)
- [Child Event Bubbling](/docs/events.md#event-bubbling)
- [Entity Events](/docs/entity-events.md)
- [View Rendering](/docs/rendering.md)
- [Prerendered Content](/docs/prerendered-dom.md)
- [View Lifecycle](/docs/lifecycle.md)

A `CollectionView` can have [`Behavior`s](/docs/behavior.md).

## Documentation Index

* [Instantiating a CollectionView](#instantiating-a-collectionview)
* [Rendering a CollectionView](#rendering-a-collectionview)
  * [Rendering a Template](#rendering-a-template)
  * [Defining the `childViewContainer`](#defining-the-childviewcontainer)
  * [Re-rendering the CollectionView](#re-rendering-the-collectionview)
* [View Lifecycle and Events](#view-lifecycle-and-events)
* [Entity Events](#entity-events)
* [DOM Interactions](#dom-interactions)
* [Behaviors](#behaviors)
* [Managing Children](#managing-children)
  * [Attaching `children` within the `el`](#attaching-children-within-the-el)
  * [Destroying All `children`](#destroying-all-children)
* [CollectionView's `childView`](#collectionviews-childview)
  * [Building the `children`](#building-the-children)
  * [Passing Data to the `childView`](#passing-data-to-the-childview)
* [CollectionView's `emptyView`](#collectionviews-emptyview)
  * [CollectionView's `getEmptyRegion`](#collectionviews-getemptyregion)
  * [Passing Data to the `emptyView`](#passing-data-to-the-emptyview)
  * [Defining When an `emptyView` shows](#defining-when-an-emptyview-shows)
* [Accessing a Child View](#accessing-a-child-view)
  * [CollectionView `children` Iterators And Collection Functions](#collectionview-children-iterators-and-collection-functions)
* [Listening to Events on the `children`](#listening-to-events-on-the-children)
* [Self Managed `children`](#self-managed-children)
  * [Adding a Child View](#adding-a-child-view)
  * [Removing a Child View](#removing-a-child-view)
  * [Detaching a Child View](#detaching-a-child-view)
  * [Swapping Child Views](#swapping-child-views)
* [Sorting the `children`](#sorting-the-children)
  * [Defining the `viewComparator`](#defining-the-viewcomparator)
  * [Maintaining the `collection`'s sort](#maintaining-the-collections-sort)
* [Filtering the `children`](#filtering-the-children)
  * [Defining the `viewFilter`](#defining-the-viewfilter)

## Instantiating a CollectionView

When instantiating a `CollectionView` there are several properties, if passed,
that will be attached directly to the instance:
`attributes`, `behaviors`, `childView`, `childViewContainer`, `childViewEventPrefix`,
`childViewEvents`, `childViewOptions`, `childViewTriggers`, `className`, `collection`,
`collectionEvents`, `el`, `emptyView`, `emptyViewOptions`, `events`, `id`, `model`,
`modelEvents`, `sortWithCollection`, `stateEvents`, `tagName`, `template`, `templateContext`,
`triggers`, `ui`, `viewComparator`, `viewFilter`

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

const myCollectionView = new CollectionView();
```

`CollectionView` composes the same visual, event, and State contracts as `View`,
but does not inherit View's named-Region methods. Use `getEmptyRegion()` for its
empty View; put a CollectionView inside a parent View when a layout needs
additional named Regions. A supplied `state` follows the
[State ownership contract](/docs/state.md#borrowed-and-owned-sources).

## Rendering a CollectionView

The `render` method of the `CollectionView` is primarily responsible
for rendering the entire collection. It loops through each of the
children in the collection and renders them individually as a
`childView`.

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

const MyCollectionView = CollectionView.extend({});

// all of the children views will now be rendered.
new MyCollectionView().render();
```

### Rendering a Template

In addition to rendering children, the `CollectionView` may have a
`template`.  The child views can be rendered within a DOM element of
this template. The `CollectionView` will serialize either the `model`
or `collection` along with context for the `template` to render.

For more detail on how to render templates, see
[View Template Rendering](/docs/rendering.md).

### Defining the `childViewContainer`

By default the `CollectionView` will render the children into the `el`
of the `CollectionView`. If you are rendering a template you will want
to set the `childViewContainer` to be a selector for an element within
the template for child view attachment.

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

const MyCollectionView = CollectionView.extend({
  childViewContainer: '.js-widgets',
  template: () => '<h1>Widgets</h1><ul class="js-widgets"></ul>'
});
```

**Errors** An error will throw if the childViewContainer can not be found.

### Re-rendering the CollectionView

If you need to re-render the entire collection or the template, you can call the
`collectionView.render` method. This method will destroy all of
the child views that may have previously been added.

## View Lifecycle and Events

Like `View`, a `CollectionView` exposes its lifecycle as the independent
`isRendered()`, `isAttached()`, and `isDestroyed()` state values. Its managed
children have their own View lifecycle state. Existing contents in the
`CollectionView` element do not make the `CollectionView` rendered; rendering
means its child set has been built and inserted into its element.

The table describes the default rendered and monitored path. Passing
`{ preventRender: true }` to `addChildView` still renders the parent when
needed, but manages the supplied child without rendering it; detaching that
child returns it in its current lifecycle state. Setting
`monitorViewEvents: false` on the `CollectionView` intentionally disables child
attachment events and automatic child `isAttached()` updates.

Disabling monitoring does not make child destruction clear surrounding template
content. Bulk removal is used only when the child container contains those Views'
root elements and optional formatting whitespace.

| Operation | CollectionView state | Managed child state |
| --- | --- | --- |
| Construct | Starts not rendered and not destroyed. It is attached only when its element is already in the document. | No children have been built. |
| `render()` | Enters rendered and preserves its attached state. Repeated render stays rendered. | Builds and renders the current children. Repeated render destroys the previous children before building replacements. |
| A rendered collection resets | Remains rendered and preserves its attached state. | Destroys the previous children and builds replacements for the reset collection. |
| `addChildView(view)` | Renders first when needed, then remains rendered. | Renders and manages the added View. |
| `detachChildView(view)` | State is unchanged. | Removes and returns the live View in a detached state. The caller becomes responsible for it. |
| `removeChildView(view)` or external child destruction | State is unchanged. | Removes the child from the managed set. `removeChildView` destroys it; an externally destroyed child is removed once. |
| The owning Region detaches and re-shows the CollectionView | Remains rendered while attached changes to `false`, then back to `true`. | Live children follow the parent's detached and attached state. |
| `destroy()` | Detaches, becomes not rendered, and enters destroyed. Repeated destroy returns the CollectionView without repeating lifecycle events. | Detaches and destroys every still-managed child after the parent element is removed. |
| `render()` after destruction | Returns the same CollectionView and remains not rendered and destroyed. Repeated calls are no-ops. | Does not recreate or render children. |
| `addChildView(view)` once destruction begins | Returns the supplied View without inspecting it, the index, or options or changing events, ownership, DOM, or lifecycle state. Calls during `before:destroy` and repeated calls after destruction are the same no-op. | The supplied View remains unchanged and can be added to a live owner. |

Collection `sort`, `reset`, and `update` events raised reentrantly during destruction
do not rebuild, add, remove, sort, render, or destroy additional child Views.

A View returned by `detachChildView()` is no longer managed by the
`CollectionView`; another owner may show it, or the caller must destroy it.
Other operations on an already destroyed `CollectionView` remain outside this
lifecycle contract until their invalid-transition behavior is made consistent.

Read More:
- [View Lifecycle](/docs/lifecycle.md)
- [View DOM Change Events](/docs/class-events.md#dom-change-events)
- [View Destroy Events](/docs/class-events.md#destroy-events)

## Entity Events

A `CollectionView` subscribes to its `model` and `collection` through the
configured [DataApi](/docs/data-api.md). Event names and callback arguments belong
to that data provider. Plain objects and arrays do not emit changes; declaring
entity event maps for unobservable values throws `MN0037`.

Read More:
- [Entity Events](/docs/entity-events.md)

## DOM Interactions

`CollectionView` uses the same native [`events`, `triggers`, and `ui`
contracts](/docs/dom-interactions.md) as `View`. Keep parent selectors and handlers
specific to DOM that the `CollectionView` itself owns. Delegation is rooted at
the parent `el`, so a broad selector can also match child-owned descendants; do
not rebind the parent's `ui` to reach into child View DOM.

After application code places parent-owned DOM inside a template-less
`CollectionView`, call `bindUIElements()` before reading it with `getUI()`. Use
that method only to bind the CollectionView's own DOM, not child View DOM.
Calling `getUI()` without a declared `ui` map or while UI elements are unbound throws
[`MN0023`](/docs/diagnostics.md#look-up-a-code).

When parent code needs a child, [retrieve the child View through the public
`children` lookup APIs](#accessing-a-child-view) and call an intentional public
method on that View. For communication initiated by a child, use
[`childViewEvents` or `childViewTriggers`](/docs/events.md#child-view-events), or an
explicit public [`listenTo`](/docs/events.md#listening-to-events) subscription,
instead of querying or mutating the child's DOM from the parent.

Read More:
- [DOM Interactions](/docs/dom-interactions.md)
- [Listening to Events on Children](#listening-to-events-on-the-children)

## Behaviors

A `Behavior` provides a clean separation of concerns to your view logic,
allowing you to share common user-facing operations between your views.

Read More:
- [Using `Behavior`s](/docs/behavior.md#using-behaviors)

## Managing Children

Children are automatically managed once the `CollectionView` is
[rendered](#rendering-a-collectionview). For each model within the
`collection` the `CollectionView` will build and store a `childView`
within its `children` object. This allows you to easily access
the views within the collection view, iterate them, find them by
a given indexer such as the view's model or id and more.

During its first render, the `CollectionView` subscribes through
`DataApi.observeCollection()` to normalized update, reset, and reorder
notifications. The configured provider owns the source event vocabulary;
[Backbone](/docs/backbone.md) is one supported observable integration.

When the `collection` for the view is `reset`, the view will destroy all
children and re-render the entire collection.

When the adapter reports a model addition, the `CollectionView` constructs its
child and renders it if it passes the presentation filter.

When a model is removed from the `collection` (or destroyed / deleted), the `CollectionView`
will destroy and remove that model's child view.

Collection updates, `sort()`, and `filter()` use the same child-rendering path.
Surviving visible children keep their elements mounted, including when a
`viewFilter` or custom `viewComparator` is active. New or newly visible children
are attached through `attachHtml`; existing elements move only when their order
needs to change. Removal alone does not move or rerender surviving children. See
[DOM movement](/docs/dom-api.md#moveelel-parent-before) for focus and text-selection
preservation and the browser fallback behavior.

The `before:render:children` and `render:children` events receive all visible
children. This describes the render pass, not a list of children whose templates
were rerendered. Already-rendered children reuse their contents unless the data
adapter reports them as updated.

Overriding `sort()` or `filter()` replaces that part of the flow. Call the parent
method to retain its behavior; CollectionView does not force a render after an
override that deliberately skips it.

When the `collection` for the view is sorted, the view by default reconciles its child
views to the collection's source order unless the `sortWithCollection` attribute on the
`CollectionView` is set to `false`. Setting `viewComparator: false` disables a separate
presentation sort; it does not disable keyed source-order reconciliation.

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

setDataApi(BackboneApi);

const collection = new Backbone.Collection();

const MyChildView = View.extend({
  template: false
});

const MyCollectionView = CollectionView.extend({
  childView: MyChildView,
  collection,
});

const myCollectionView = new MyCollectionView();

// Collection view will not re-render as it has not been rendered
collection.reset([{foo: 'foo'}]);

myCollectionView.render();

// Collection view will effectively re-render displaying the new model
collection.reset([{foo: 'bar'}]);
```

When the children are rendered the
[`render:children` and `before:render:children` events](/docs/class-events.md#renderchildren-and-beforerenderchildren-events)
will trigger.

When a childview is added to the children
[`add:child` and `before:add:child` events](/docs/class-events.md#addchild-and-beforeaddchild-events)
will trigger

When a childview is removed from the children
[`remove:child` and `before:remove:child` events](/docs/class-events.md#removechild-and-beforeremovechild-events)
will trigger.

### Attaching `children` within the `el`

The `CollectionView` places new or newly visible child root elements into a
`DocumentFragment`, then calls `attachHtml(fragment, container)` to insert that
batch. Already mounted children remain in place or move only as needed to match
the presentation order; they are not all removed and appended on each pass.

You can override this by specifying an `attachHtml` method in your
view definition. This method takes two parameters and has no return value.

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

CollectionView.extend({

  // The default implementation:
  attachHtml(els, container) {
    // Unless childViewContainer is set, container === this.el
    this.Dom.appendContents(container, els);
  }
});
```

The first parameter is the DOM fragment containing child root elements, and the second parameter
is the native DOM container for the children which by default equates
to the view's `el` unless a [`childViewContainer`](#defining-the-childviewcontainer)
is set.

### Destroying All `children`

`CollectionView` implements a `destroy` method which automatically
destroys its children and cleans up listeners.

When a nonempty owned child set is destroyed, the
[`destroy:children` and `before:destroy:children` events](/docs/class-events.md#destroychildren-and-beforedestroychildren-events)
will trigger.

Read More:
- [View Destroy Events](/docs/class-events.md#destroy-events)

## CollectionView's `childView`

When using a `collection` to manage the children of `CollectionView`,
specify a Marionette `View` or `CollectionView` class as `childView`, rather
than an instance. A plain Backbone View is not a supported child;
[wrap it in a Marionette View](/docs/region.md#wrapping-a-non-marionette-view)
when integrating a legacy component.

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

const MyChildView = View.extend({});

const MyCollectionView = CollectionView.extend({
  childView: MyChildView
});
```

**Errors** When Marionette needs to construct a collection-backed child and
`childView` is missing, it throws `MN0011`. An empty CollectionView or a
CollectionView with only manually added children does not require `childView`.

You can also define `childView` as a function. In this form, the value
returned by this method is the `ChildView` class that will be instantiated
when a `Model` needs to be initially rendered. This method also gives you
the ability to customize per `Model` `ChildViews`.

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

setDataApi(BackboneApi);

const FooView = View.extend({
  template: _.template('foo')
});

const BarView = View.extend({
  template: _.template('bar')
});

const MyCollectionView = CollectionView.extend({
  collection: new Backbone.Collection(),
  childView(model) {
    // Choose which view class to render,
    // depending on the properties of the model
    if  (model.get('isFoo')) {
      return FooView;
    }
    else {
      return BarView;
    }
  }
});

const collectionView = new MyCollectionView().render();

const foo = new Backbone.Model({
  isFoo: true
});

const bar = new Backbone.Model({
  isFoo: false
});

// Renders a FooView
collectionView.collection.add(foo);

// Renders a BarView
collectionView.collection.add(bar);
```

A resolver must return a Marionette View class. Core trusts that result;
unsupported returns can fail later during construction or child setup.

### Building the `children`

The `buildChildView` method is responsible for taking the ChildView class and
instantiating it with the appropriate data. This method takes three
parameters and returns a view instance to be used as the child view.

```javascript
buildChildView(child, ChildViewClass, childViewOptions){
  // build the final list of options for the childView class
  const options = { model: child, ...childViewOptions };
  // create the child view instance
  const view = new ChildViewClass(options);
  // return it
  return view;
},
```

Override this method when you need a more complicated build, but use [`childView`](#collectionviews-childview)
if you need to determine _which_ View class to instantiate.

```javascript
import _ from 'underscore';
import BackboneApi from '@mnjs/adapters/backbone';
import Backbone from 'backbone';
import { CollectionView, setDataApi } from 'marionette';
import MyListView from './my-list-view';
import MyView from './my-view';

setDataApi(BackboneApi);

const MyCollectionView = CollectionView.extend({
  childView(child) {
    if (child.get('type') === 'list') {
      return MyListView;
    }

    return MyView;
  },
  buildChildView(child, ChildViewClass, childViewOptions) {
    let options;

    if (child.get('type') === 'list') {
      const childList = new Backbone.Collection(child.get('list'));
      options = _.extend({collection: childList}, childViewOptions);
    } else {
      options = _.extend({model: child}, childViewOptions);
    }

    // create the child view instance
    const view = new ChildViewClass(options);
    // return it
    return view;
  }
});
```

### Passing Data to the `childView`

There may be scenarios where you need to pass data from your parent
collection view in to each of the childView instances. To do this, provide
a `childViewOptions` definition on your collection view as an object
literal. This will be passed to the constructor of your childView as part
of the `options`.

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

const ChildView = View.extend({
  initialize(options) {
    console.log(options.foo); // => "bar"
  }
});

const MyCollectionView = CollectionView.extend({
  childView: ChildView,

  childViewOptions: {
    foo: 'bar'
  }
});
```

You can also specify the `childViewOptions` as a function, if you need to
calculate the values to return at runtime. The model will be passed into
the function should you need access to it when calculating
`childViewOptions`. The function may return an object, `null`, or `undefined`. The attributes
of a returned object will be copied to the `childView` instance's options. Whether
provided directly or returned by a function, the object's own enumerable
properties, including symbols, are copied by object spread. `null` or `undefined`
adds no extra options. A supplied `model` option overrides the source model;
use that only when the child deliberately represents different data.

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

const MyCollectionView = CollectionView.extend({
  childViewOptions(model) {
    // do some calculations based on the model
    return {
      foo: 'bar'
    };
  }
});
```

## CollectionView's `emptyView`

When a collection has no children, and you need to render a view other than
the list of childViews, you can specify an `emptyView` attribute on your
collection view. The `emptyView`, like the
[`childView`](#collectionviews-childview), can be passed as an option on
instantiation. It must be a `View` class or a resolver that returns a `View`
class. Marionette calls resolvers with the `CollectionView` as `this`; arrow and
bound functions retain their normal JavaScript `this` semantics.

If the resolved `emptyView` property is `undefined`, `null`, or `false`, no
empty view is rendered. Because an `undefined` constructor option does not
replace an inherited value, use `null` or `false` to disable an inherited
definition. A resolver may return a `View` class or `undefined`, `null`, or
`false` to disable the empty view. The public types describe these alternatives;
Marionette trusts the result when the collection is empty. Errors thrown by a
resolver propagate unchanged.

When the empty collection is rendered or filtered again, a disabled result also
removes any empty View already shown.

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

const MyEmptyView = View.extend({
  template: _.template('Nothing to display.')
});

const MyCollectionView = CollectionView.extend({
  // ...

  emptyView: MyEmptyView
});
```

### CollectionView's `getEmptyRegion`

When a `CollectionView` is instantiated it creates a region for showing the [`emptyView`](#collectionviews-emptyview).
This region can be requested using the `getEmptyRegion` method. It uses the
resolved `childViewContainer` when present, otherwise the CollectionView's `el`,
and is shown with [`replaceElement: false`](/docs/region.md#additional-options).

**Note** The `CollectionView` expects to be the only entity managing the region.
Showing things in this region directly is not advised.

```javascript
const isEmptyShowing = myCollectionView.getEmptyRegion().hasView();
```

This region can be useful for handling the
[EmptyView Region Events](/docs/class-events.md#collectionview-emptyview-region-events).

### Passing Data to the `emptyView`

Similar to [`childView`](#collectionviews-childview) and [`childViewOptions`](#passing-data-to-the-childview),
there is an `emptyViewOptions` property that will be passed to the `emptyView` constructor.
It can be provided as an object literal or as a function.

If `emptyViewOptions` aren't provided, the `CollectionView` falls back to
`childViewOptions`. A callable definition receives no model argument and runs
with the CollectionView as `this`; it must support that empty-view call.

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

const EmptyView = View.extend({
  initialize(options){
    console.log(options.foo); // => "bar"
  }
});

const MyCollectionView = CollectionView.extend({
  emptyView: EmptyView,

  emptyViewOptions: {
    foo: 'bar'
  }
});
```

### Defining When an `emptyView` shows

If you want to control when the empty view is rendered, you can override
`isEmpty`:

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

const MyCollectionView = CollectionView.extend({
  isEmpty() {
    // some logic to calculate if the view should be rendered as empty
    return this.collection.length < 2;
  }
});
```

The default implementation of `isEmpty` returns `!this.children.length`.

Use `getEmptyRegion().hasView()` to determine whether an empty View is actually
shown. `isEmpty()` alone does not establish that an `emptyView` was configured:

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

const MyCollectionView = CollectionView.extend({
  // ...
  onRenderChildren() {
    if (this.getEmptyRegion().hasView()) { console.log('Empty View Shown'); }
  }
});
```

## Accessing a Child View

You can retrieve a view by a number of methods. If the findBy* method cannot find the view,
it will return `undefined`.

**Note** `children` is the current presentation container. It can include
unrendered children added with `preventRender` until the next render/filter
pass; filtered-out children remain owned but are absent from this container.

#### CollectionView `children`'s: `findByCid`
Find a view by its cid.

```javascript
const bView = myCollectionView.children.findByCid(buttonView.cid);
```

#### CollectionView `children`'s: `findByModel`
Find a view by `DataApi.key(model)`. With the default DataApi this is the
model object identity. An adapter may use a stable key so that a new model
object representing the same item resolves the currently indexed child. This
lookup does not promise child retention when a collection observation replaces
the model object; see [collection observations](/docs/data-api.md#collection-observations).

```javascript
const bView = myCollectionView.children.findByModel(buttonView.model);
```

#### CollectionView `children`'s: `findByKey`

`children.findByKey(key)` returns the View indexed by the exact key produced by
its DataApi, or `undefined` when absent. Do not assume this key is the model's
`id`: native Marionette and Backbone models use their provider's identity
contract, while snapshot adapters can use an application-selected key.

`children.hasView(view)` checks that the exact View instance is present under
its `cid`; `children.contains(view)` checks instance membership as well.
These lookups refer to the public presentation container. A filtered-out child
can remain owned by the CollectionView without appearing in `children`. Keep
an explicit reference when an application needs to detach such a child; do not
reach into private containers.

#### CollectionView `children`'s: `findByIndex`

Find by numeric index (unstable)

```javascript
const bView = myCollectionView.children.findByIndex(0);
```

#### CollectionView `children`'s: `findIndexByView`

Find the index of the exact View inside `children`, or `-1` when absent.

```javascript
const index = myCollectionView.children.findIndexByView(bView);
```

### CollectionView `children` Iterators And Collection Functions

The container is iterable: `for (const child of list.children)` visits the
current presentation order. Use `children.toArray()` when you need a separate
array before changing membership.

The container owns the following iteration and collection functions:

* `each`
* `map`
* `reduce`
* `find`
* `filter`
* `reject`
* `every`
* `some`
* `contains`
* `invoke`
* `toArray`
* `first`
* `initial`
* `rest`
* `last`
* `without`
* `isEmpty`
* `pluck`
* `partition`

These methods can be called directly on the container, to iterate and process
the views held by the container.

`each`, `map`, `reduce`, `find`, `filter`, `reject`, `every`, `some`, and
`partition` require callback functions. The public types enforce that contract;
unsupported JavaScript callback shapes have no guaranteed Marionette diagnostic.
String, object, and null iteratee shorthand is not supported. Structurally adding, removing, or
reordering children while a callback runs is unsupported, and these methods do
not promise call-start snapshot semantics. Mutating ordinary properties on a
child View remains valid.

`each(callback, context)` visits every child View in order, calls `callback` as
`(view, index)`, binds `this` to `context` when provided, and returns the
`children` container. An empty container returns itself without calling the
callback.

`map(callback, context)` calls `(view, index)` for every child View and returns a
new ordered array of callback results. An empty container returns a new `[]`.
Use `map(view => view.id)` or `pluck('id')` instead of property-name shorthand.

`reduce(callback, initialValue, context)` calls
`(accumulator, view, index)` in container order and binds optional `context`.
When `initialValue` is supplied, every child View is visited; an empty container
returns that exact value without calling the callback. When it is omitted, the
first child View becomes the accumulator and traversal starts at index `1`. An
empty container without an initial value throws [`MN0024`](/docs/diagnostics.md#look-up-a-code).

`pluck(key)` reads `key` directly from each child View. For example,
`children.pluck('model')` returns the child Views' model objects, and a child
without a model contributes `undefined`. It does not read model attributes; use
an explicit callback such as `children.map(view => view.model?.get('status'))`
for those values. Array-form deep paths are not traversed; replace
`children.pluck(['model', 'cid'])` with
`children.map(view => view.model?.cid)`. An empty container returns `[]`.

`contains(value)` checks for the exact child View instance. A child View's model
or another object with the same properties is not considered contained. An empty
container returns `false`.

`find`, `filter`, `reject`, `every`, `some`, and `partition` call their predicate
with `(view, index)` and set `this` to optional `context`.

`find(predicate, context)` returns the first child View for which the predicate
is truthy, preserving View identity, and stops iterating at that match. It
returns `undefined` when no View matches or the container is empty.

`filter(predicate, context)` and `reject(predicate, context)` visit every child
View and return new ordered arrays containing the Views for which the predicate
is truthy or falsey, respectively. Changing a returned array does not change the
container. An empty container returns `[]` without calling the predicate.

`every(predicate, context)` returns `false` and stops at the first falsey result;
otherwise it returns `true`. `some(predicate, context)` returns `true` and stops
at the first truthy result; otherwise it returns `false`. For an empty container,
`every` returns `true` and `some` returns `false`, without calling the predicate.

`partition(predicate, context)` visits every child View and returns
`[matchingViews, rejectedViews]`. Both members are new arrays that preserve the
container order and contain the exact child View instances. An empty container
returns `[[], []]` without calling the predicate.

`invoke(methodName, ...args)` requires a direct string method name, invokes that
method with each child View as `this`, forwards `args`, and returns a new ordered
array of results. TypeScript restricts the name to callable child methods and
checks their arguments and result types. Function-form and deep-path method
names are not supported. An empty container returns `[]`.

`toArray()` returns a new array containing the current child Views in container
order. Changing the returned array's membership or order does not change the
container. An empty container returns `[]`.

Without a count, `first()` and `last()` return the first or last child View. With
a nonnegative integer count, they return a new ordered array containing up to
that many Views from the corresponding end of the container. A count of `0`
returns `[]`. For an empty container, the no-count forms return `undefined` and
the count forms return `[]`.

`initial(count = 1)` and `rest(count = 1)` return new ordered arrays after
excluding `count` Views from the end or start of the container, respectively.
The count is a nonnegative integer: `0` returns a new array of every child View,
and a count greater than or equal to the container length returns `[]`. An empty
container also returns `[]`. `first`, `initial`, `rest`, and `last` throw
[`MN0024`](/docs/diagnostics.md#look-up-a-code) when a supplied count is not a nonnegative integer.

`without(...views)` returns a new ordered array excluding the exact child View
instances supplied. Models and lookalike objects do not exclude their associated
Views. With no arguments it returns a new array of every child View. Changing the
returned array's membership or order does not change the container. An empty
container returns `[]`.

`children.isEmpty()` reports whether the child container currently has zero
Views. It is distinct from the overridable `CollectionView#isEmpty()` method,
which controls whether a CollectionView renders its `emptyView`.

The child container is iterable. `for...of`, spread, destructuring, and
`Array.from(children)` yield the exact child View instances in container order.
The iterator is defined once on the prototype rather than allocated as an own
property on every container.

The former undocumented Underscore aliases `forEach`, `detect`, `select`, `all`,
`any`, and `include` are not part of the v5 container. Use `each`, `find`,
`filter`, `every`, `some`, and `contains`, respectively.

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

setDataApi(BackboneApi);

const collectionView = new CollectionView({
  collection: new Backbone.Collection()
});

collectionView.render();

// iterate over all of the views and process them
collectionView.children.each(function(childView) {
  // process the `childView` here
});
```

## Listening to Events on the `children`

The `CollectionView` can take action depending on what
events are triggered in its `children`.

Read More:
- [Child Event Bubbling](/docs/events.md#event-bubbling)

## Self-Managed `children`

In addition to children added by Marionette matching the model of a `collection`,
the `children` of the `CollectionView` can be manually managed.

### Adding a Child View

The `addChildView` method can be used to add a view that is independent of your
collection source. This method takes three parameters, the child view instance,
optionally the index for where it should be placed within the
[CollectionView's `children`](#managing-children), and an options hash.
It returns the added view.

<!-- executable-example: collectionview-child-ownership -->
```javascript
import { CollectionView, View } from 'marionette';

const ChildView = View.extend({
  tagName: 'li',
  template() {
    return 'Model';
  }
});

export function runChildOwnershipLifecycle() {
  const collectionView = new CollectionView({ tagName: 'ul' });
  const reusableChild = new ChildView();
  const remainingChild = new ChildView();

  collectionView.render();
  collectionView.addChildView(reusableChild);

  const detachedChild = collectionView.detachChildView(reusableChild);
  collectionView.addChildView(detachedChild);
  collectionView.removeChildView(detachedChild);

  collectionView.addChildView(remainingChild);
  collectionView.destroy();
}
```

`detachChildView()` returns the same live View and transfers responsibility to
the caller. That View may be added again without rendering it a second time.
`removeChildView()` destroys the removed View, while destroying the
`CollectionView` destroys every child that it still manages.

An omitted or `null` index appends the child before sorting and filtering.
The options-only form follows the same rule; use a numeric `index` to choose
an insertion position.

A numeric index bypasses sorting and filtering for that addition only. A later
`sort()` or `filter()` processes the child normally. The numeric `index` in an
options object takes precedence over the separate positional argument.

**Errors** Adding a View that is still managed by a Region or
`CollectionView` throws [`MN0003`](/docs/diagnostics.md#look-up-a-code). Detach the View from its
current owner before transferring it.

Filtering a child out or adding it with `preventRender` still leaves it managed
by that CollectionView. Use `detachChildView()` to transfer it to another owner.

#### `preventRender` option

If you wish to add a child view to the children without the collectionview rendering
the children use the `preventRender` option.

```javascript
import { CollectionView } from 'marionette';
import ButtonView from './button-view';

const myCollectionView = new CollectionView();

const insertIndex = 0; // Add to the top

myCollectionView.addChildView(new ButtonView(), { preventRender: true, index: insertIndex });
myCollectionView.addChildView(new ButtonView(), insertIndex, { preventRender: true });
myCollectionView.addChildView(new ButtonView());  // renders all three children
```

### Removing a Child View

The `removeChildView` method is useful if you need to remove and destroy a view from
the `CollectionView` without affecting the view's collection.  In most cases it is
better to use the data to determine what the `CollectionView` should display.

This method accepts the child view instance to remove as its parameter. It returns
the removed view.

Later updates to the retained model do not recreate its removed View. Rendering
the CollectionView again or resetting its collection rebuilds its children from
the current collection.

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

// Fragment for a collection using the Backbone DataApi.
const MyCollectionView = CollectionView.extend({
  childViewEvents: { 'foo:event': 'onChildViewFooEvent' },
  onChildViewFooEvent(childView, model) {
    // NOTE: we must wait for the server to confirm
    // the destroy PRIOR to removing it from the collection
    model.destroy({wait: true});

    // but go ahead and remove it visually
    this.removeChildView(childView);
  }
});
```

### Detaching a Child View

The `detachChildView` method is the same as [`removeChildView`](#removing-a-child-view)
with the exception that the removed view is not destroyed.

### Swapping Child Views

Swap the location of two views in the `CollectionView` `children` and in the `el`.
This can be useful when sorting is arbitrary or is not performant.

**Errors** If either of the two views aren't part of the `CollectionView` an error will be thrown.

If only one of the two children is in the presentation `children` container,
[filter](#filtering-the-children) is called after swapping their owned order.

```javascript
import BackboneApi from '@mnjs/adapters/backbone';
import Backbone from 'backbone';
import { CollectionView, setDataApi } from 'marionette';
import MyChildView from './my-child-view';

setDataApi(BackboneApi);

const collection = new Backbone.Collection([
  { name: 'first' },
  { name: 'middle' },
  { name: 'last' }
]);

const myColView = new CollectionView({
  collection: collection,
  childView: MyChildView
});

myColView.render();
myColView.swapChildViews(myColView.children.first(), myColView.children.last());

myColView.children.first().model.get('name'); // "last"
myColView.children.last().model.get('name'); // "first"
```

## Sorting the `children`

The `sort` method will loop through the `CollectionView` `children` prior to filtering
and sort them with the [`viewComparator`](#defining-the-viewcomparator).
By default, if a `viewComparator` is not set, the `CollectionView` will sort
the views by the order of the models in the `collection`. If set to `false`,
presentation sorting is disabled. Normalized collection observations still reconcile
the keyed children to source order when `sortWithCollection` is enabled.

This method is called internally when rendering.
[`sort` and `before:sort` events](/docs/class-events.md#sort-and-beforesort-events)
fire when owned children exist and a comparator is active.

By default the `CollectionView` will maintain a sorted collection's order
in the DOM. This behavior can be disabled by specifying `{sortWithCollection: false}`
on initialize.

Default source ordering uses each notification's captured snapshot. A nested
notification waits for the current sort, filter, and render pass to finish.
Calling `sort()` outside a collection notification reads the current source
after `before:sort`. With the default comparator, manually added children whose
models are absent from the source stay before the source children.

Custom comparators still determine their own order and data reads. With
`sortWithCollection` enabled, source order breaks ties and manually added
children follow source children on ties. With it disabled, ties retain the
existing child order.

### Defining the `viewComparator`

`CollectionView` allows for a custom `viewComparator` option if you want your
`CollectionView`'s children to be rendered with a different sort order than the
underlying collection uses.

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

const RowView = View.extend({ template: ({ rank }) => String(rank) });
const myCollectionView = new CollectionView({
  collection: [{ rank: 2 }, { rank: 1 }],
  childView: RowView,
  viewComparator: 'rank'
});
```

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

setDataApi(BackboneApi);
const RowView = View.extend({ template: ({ id }) => String(id) });

const myCollection = new Backbone.Collection([
  { id: 1 },
  { id: 4 },
  { id: 3 },
  { id: 2 }
]);

myCollection.comparator = 'id';

const myDescendingView = new CollectionView({
  childView: RowView,
  collection: myCollection,
  viewComparator: childView => -childView.model.id
});

const mySourceOrderView = new CollectionView({
  childView: RowView,
  collection: myCollection,
  viewComparator: false
});

myDescendingView.render(); // 4 3 2 1
mySourceOrderView.render(); // 1 4 3 2

myCollection.sort();
// myDescendingView remains 4 3 2 1
// mySourceOrderView reconciles to source order: 1 2 3 4
```

A `viewComparator` can be a one-argument criterion function, a two-argument
comparison function, or a string naming a model attribute read through DataApi.
Functions receive child Views, not models, and run with the CollectionView as
`this`. These forms do not require Backbone.

A string or single-argument comparator evaluates one criterion per child View and
sorts stably. Equal, `NaN`, or otherwise incomparable criteria retain their existing
order, while `undefined` criteria sort last. A string comparator therefore places a
child without a model last. Two-argument comparators retain native `Array#sort`
semantics. Sorting keeps the same `children` container in use. If evaluating or
comparing a single-argument criterion throws, the error propagates without changing
the child order.

#### `getComparator`

Override this method to determine which `viewComparator` to use.

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

setDataApi(BackboneApi);

const MyCollectionView = CollectionView.extend({
  sortAsc(view) {
    return view.model.get('order');
  },
  sortDesc(view) {
    return -view.model.get('order');
  },
  getComparator() {
    // The collectionView's model
    if (this.model.get('sorted') === 'ASC') {
      return this.sortAsc;
    }

    return this.sortDesc;
  }
});
```

#### `setComparator`

The `setComparator` method updates `viewComparator` and calls `sort()` when the
value changes. `{ preventRender: true }` defers that sort/filter/child-render
pass. It returns the CollectionView and does not run the parent
`before:render`/`render` lifecycle. Call it after initial rendering, or defer the
pass until the initial `render()`.

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

const RowView = View.extend({ template: ({ orderBy }) => String(orderBy) });
const cv = new CollectionView({
  collection: [{ orderBy: 2 }, { orderBy: 1 }],
  childView: RowView
});

cv.render();

// Note: the setComparator is preventing the automatic re-render
cv.setComparator('orderBy', { preventRender: true });

// Apply the order without rebuilding the children or parent template
cv.sort();
```

#### `removeComparator`

This function is actually an alias of `setComparator(null, options)`. It is useful
for removing the comparator. `removeComparator` also accepts `preventRender` as a option.

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

const RowView = View.extend({ template: ({ orderBy }) => String(orderBy) });
const cv = new CollectionView({
  collection: [{ orderBy: 2 }, { orderBy: 1 }],
  childView: RowView
});

cv.render();

cv.setComparator('orderBy');

//Remove the current comparator without rendering again.
cv.removeComparator({ preventRender: true });
```

### Maintaining the `collection`'s sort

By default the `CollectionView` will maintain a sorted collection's order
in the DOM. This behavior can be disabled by specifying `{sortWithCollection: false}`
on initialize or on the view definiton.

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

setDataApi(BackboneApi);
const RowView = View.extend({ template: ({ id }) => String(id) });

const myCollection = new Backbone.Collection([
  { id: 1 },
  { id: 4 },
  { id: 3 },
  { id: 2 }
]);

myCollection.comparator = 'id';

const mySortedColView = new CollectionView({
  childView: RowView,
  collection: myCollection
});

const myUnsortedColView = new CollectionView({
  childView: RowView,
  collection: myCollection,
  sortWithCollection: false
});

mySortedColView.render(); // 1 4 3 2
myUnsortedColView.render(); // 1 4 3 2

myCollection.sort();
// mySortedColView auto-renders 1 2 3 4
// myUnsortedColView has no change
```

## Filtering the `children`

The `filter` method will loop through the `CollectionView`'s sorted `children`
and test them against the [`viewFilter`](#defining-the-viewfilter).
The views that pass the `viewFilter` are rendered if necessary and attached
to the CollectionView and the views that are filtered out will be detached.
After filtering the `children` will only contain the views to be attached.

If owned children exist and an active `viewFilter` is applied, the
[`filter` and `before:filter` events](/docs/class-events.md#filter-and-beforefilter-events)
will trigger.

The CollectionView refilters during normalized collection updates and sorting.
An arbitrary child property change does not itself trigger filtering; call
`filter()` when application-owned presentation criteria change.

**Note** This is a presentation functionality used to easily filter in and out
constructed children. All children of a `collection` will be instantiated once
regardless of their filtered status. If you would prefer to manage child view
instantiation, you should filter the `collection` itself.

### Defining the `viewFilter`

`CollectionView` allows for a custom `viewFilter` option if you want to prevent
some of the underlying `children` from being attached to the DOM.
A `viewFilter` can be a function, predicate object, or string. Use `null` or
`false` to disable it. Other shapes are unsupported; core does not guarantee
a diagnostic for an invalid filter.

#### `viewFilter` as a function

The `viewFilter` function takes a view from the `children` and returns a truthy
value if the child should be attached, and a falsey value if it should not.
It runs with the `CollectionView` as `this` and receives the child View, index,
and the live backing child array. A filter pass captures the array's initial
length, visits every index densely, and does not visit entries appended during
that pass.

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

setDataApi(BackboneApi);
const SomeChildView = View.extend({ template: ({ value }) => String(value) });
const SomeEmptyView = View.extend({ template: () => 'No matches' });

const cv = new CollectionView({
  childView: SomeChildView,
  emptyView: SomeEmptyView,
  collection: new Backbone.Collection([
    { value: 1 },
    { value: 2 },
    { value: 3 },
    { value: 4 }
  ]),

  // Only show views with even values
  viewFilter(view, index, children) {
    return view.model.get('value') % 2 === 0;
  }
});

// renders the views with values '2' and '4'
cv.render();
```

#### `viewFilter` as a predicate object

The `viewFilter` predicate object will filter against the view's model attributes.
Each filter pass snapshots the predicate's own enumerable string keys and values
in standard JavaScript own-key order. Inherited, symbol, and non-enumerable keys
are ignored. Every predicate key must exist in the model attributes and its value
must compare strictly equal; nested objects therefore match by identity. Arrays
are not predicate objects.

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

setDataApi(BackboneApi);
const SomeChildView = View.extend({ template: ({ value }) => String(value) });
const SomeEmptyView = View.extend({ template: () => 'No matches' });

const cv = new CollectionView({
  childView: SomeChildView,
  emptyView: SomeEmptyView,
  collection: new Backbone.Collection([
    { value: 1 },
    { value: 2 },
    { value: 3 },
    { value: 4 }
  ]),

  // Only show views with value 2
  viewFilter: { value: 2 }
});

// renders the view with values '2'
cv.render();
```

#### `viewFilter` as a string

The `viewFilter` string represents the view's model attribute and will filter
truthy values.

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

setDataApi(BackboneApi);
const SomeChildView = View.extend({ template: ({ value }) => String(value) });
const SomeEmptyView = View.extend({ template: () => 'No matches' });

const cv = new CollectionView({
  childView: SomeChildView,
  emptyView: SomeEmptyView,
  collection: new Backbone.Collection([
    { value: 0 },
    { value: 1 },
    { value: 2 },
    { value: null },
    { value: 4 }
  ]),

  // Only show views 1,2, and 4
  viewFilter: 'value'
});

// renders the view with values '1', '2', and '4'
cv.render();
```

#### `getFilter`

Override this function to programatically decide which
`viewFilter` to use when `filter` is called.

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

setDataApi(BackboneApi);

const MyCollectionView = CollectionView.extend({
  summaryFilter(view) {
    return view.model.get('type') === 'summary';
  },
  getFilter() {
    if (this.collection.length > 100) {
      return this.summaryFilter;
    }
    return this.viewFilter;
  }
});
```

#### `setFilter`

The `setFilter` method updates `viewFilter` and calls `filter()` when the value
changes. `{ preventRender: true }` defers that filter/child-render pass. It
returns the CollectionView without running the parent render lifecycle. Call
it after initial rendering, or defer the pass until the initial `render()`.

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

setDataApi(BackboneApi);
const RowView = View.extend({ template: ({ value }) => String(value) });
const cv = new CollectionView({
  collection: new Backbone.Collection([{ value: 1 }, { value: 2 }]),
  childView: RowView
});

cv.render();

const newFilter = function(view, index, children) {
  return view.model.get('value') % 2 === 0;
};

// Note: the setFilter is preventing the automatic re-render
cv.setFilter(newFilter, { preventRender: true });

// Apply the new filter while retaining surviving child instances.
cv.filter();
```

#### `removeFilter`

This function is actually an alias of `setFilter(null, options)`. It is useful
for removing filters. `removeFilter` also accepts `preventRender` as a option.

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

setDataApi(BackboneApi);
const RowView = View.extend({ template: ({ value }) => String(value) });
const cv = new CollectionView({
  collection: new Backbone.Collection([{ value: 1 }, { value: 2 }]),
  childView: RowView
});

cv.render();

cv.setFilter(function(view, index, children) {
  return view.model.get('value') % 2 === 0;
});

// Remove the current filter without rendering again.
cv.removeFilter({ preventRender: true });
```


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