Array Controllers in Ember.js
An array controller is a wrapper for a collection of objects, and provides convenient methods for dealing with its contents.
An array controller’s model
is typically set in a route, for example:
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
{name: 'red'},
{name: 'yellow'},
{name: 'blue'}
];
}
});
// (The Index ArrayController is setup implicitly)
Setting an array controller’s model
sets up its content
property, which forms the basis for other properties and methods.
arrangedContent
arrangedContent
is an important property, defined as “the array that the [array controller] pretends to be”. It provides a way for sorted/filtered content to be stored separately from the original content
. In this way, sorting/filtering is not destructive, and the content (in its original form) can still be retrieved.
By default, when an array controller has no sortProperties
, arrangedContent
and content
are the same. When sortProperties
are added, the sorted content is stored in arrangedContent
whilst the original content
remains untouched.
It’s important to note that an array controller should be treated just like an array, with its items referencing those in arrangedContent
. Accessing items on an array controller itself, is effectively the same as accessing items in arrangedContent
(an important difference is discussed in below).
This is best illustrated with some examples. Given the route above, the following #each
loops all result in the same output:
index
template:
{{#each}} {{name}} {{/each}}
{{#each content}} {{name}} {{/each}}
{{#each arrangedContent}} {{name}} {{/each}}
http://emberjs.jsbin.com/nuzoja/1
Setting sortProperties
results in sorted output from arrangedProperty
and therefore from the array controller instance itself:
App.IndexController = Ember.ArrayController.extend({
sortProperties: ['name']
});
index
template:
{{!-- Sorted by name --}}
{{#each}}
{{!-- Not Sorted --}}
{{#each content}}
{{!-- Sorted by name --}}
{{#each arrangedContent}}
Item Controllers
Adding an itemController
property to an array controller wraps each item in an instance of the referenced controller. However, this only applies when accessing items through the array controller instance itself. Items accessed via arrangedContent
or content
remain unwrapped. This is the key difference when accessing items via arrangedContent
versus accessing them via the array controller instance itself.
The following example demonstrates this concept:
App.IndexController = Ember.ArrayController.extend({
itemController: 'color'
});
App.ColorController = Ember.ObjectController.extend({
isActive: true
});
index
template:
{{!-- Names rendered --}}
{{#each}}
{{#if isActive}} {{name}} {{/if}}
{{/each}}
{{!-- Nothing rendered --}}
{{#each content}}
{{#if isActive}} {{name}} {{/if}}
{{/each}}
{{!-- Nothing rendered --}}
{{#each arrangedContent}}
{{#if isActive}} {{name}} {{/if}}
{{/each}}
http://emberjs.jsbin.com/nuzoja/3/edit
Nothing is rendered in the loops that iterate over content
or arrangedContent
because the items are not wrapped in an item controller and therefore isActive
is inaccessible.
{{#each itemController='…'}}
{{#each}}
helpers, when supplied with an itemController
property, wrap each item in a new instance of the referenced controller. This operates entirely independently from the itemController
property on an array controller: an array controller will not have access to any item controller created via an {{#each}}
helper.
This becomes particularly important when implementing a computed property on an array controller that depends on properties on an item controller. See the example.
For more information:
- Ember.ArrayController Documentation
- The
#each
helper post on ember.guru - Array Computed Properties talk by David Hamilton