What is a Controller?
A Controller is routable object which receives a single property from the Route – model
– which is the return value of the Route's model()
method.
The model is passed from the Route to the Controller by default using the setupController()
function. The Controller is then often used to decorate the model with display properties such as retrieving the full name from a name model.
A Controller is usually paired with an individual Route of the same name.
Defining a Controller
We only need to generate a Controller file if we want to customize the properties or provide any actions to the Route. If we have no customizations, Ember will provide a default Controller instance for us at run time.
To generate a controller, run
ember generate controller my-controller-name
This creates a controller file at app/controllers/my-controller-name.js
, and a unit test file at tests/unit/controllers/my-controller-name-test.js
.
The controller name my-controller-name
must match the name of the Route that renders it. So if the Route is named blog-post
, it should have a matching Controller named blog-post
. The matching file names of the Controller and the Route signals to Ember that this Controller must be used when landing on the blog-post
Route.
Where and When to use Controllers?
Controllers are used as an extension of the model loaded from the Route. Any attributes or actions that we want to share with components used on that Route could be defined on the Controller and passed down through the Route’s template.
Controllers are singletons so we should avoid keeping state that does not derive from either the Model or Query Parameters since these would persist in between activations such as when a user leaves the Route and then re-enters it.
Controllers can also contain actions that enable the Route's components to update the Model or Query Parameters through it using Computed Properties.
Basic Controller Example
Let's explore these concepts using an example of a route displaying a blog post. Assume that the route returns a BlogPost
model that is presented in the template.
The BlogPost
model would have properties like:
title
intro
body
author
In the example below, we can see how the template is using the model properties to display some data.
Consider the example where we want to have a controller for a blog-post
route. In this controller, we are looking to keep track if the user has expanded the body or not.
import Controller from '@ember/controller';
export default Controller.extend({
isExpanded: false,
actions: {
toggleBody() {
this.toggleProperty('isExpanded');
}
}
});
The property isExpanded
keeps track if the user has expanded the body or not. The action toggleBody()
provides a way for the user to provide their setting. Both of the them are used in the updated template below.
We can see that if the property isExpanded
is toggled to true, we will show the body property of the model to the user. This isExpanded
is stored in the controller.
Common questions
Should we use controllers in my application? I've heard they're going away!
Yes! Controllers are still an integral part of an Ember application architecture, and generated by the framework even if you don't declare a Controller module explicitly.
When should we create a Controller?
- We want to pass down actions or variables to share with a Route’s child components
- We have a computed property that depends on the results of the model hook
- We need to support query parameters