Old Guides - You are viewing the guides for Ember v3.12.0. VIEW v3.28.0
Edit Page

Introduction


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.

Routing Query Parameters should be defined within a controller.

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.

<h1>{{this.model.title}}</h1>
<h2>by {{this.model.author}}</h2>

<div class="intro">
  {{this.model.intro}}
</div>
<hr>
<div class="body">
  {{this.model.body}}
</div>

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 them are used in the updated template below.

<h1>{{this.model.title}}</h1>
<h2>by {{this.model.author}}</h2>

<div class='intro'>
  {{this.model.intro}}
</div>
<hr>

{{#if this.isExpanded}}
  <button {{action "toggleBody"}}>Hide Body</button>
  <div class="body">
    {{this.model.body}}
  </div>
{{else}}
  <button {{action "toggleBody"}}>Show Body</button>
{{/if}}

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