cult3

Introducing Controllers and Models to an Ember.js Application

Jun 29, 2015

Table of contents:

  1. Iterating through a list of tasks
  2. Creating a Controller
  3. Adding a Model
  4. Conclusion

In last week’s tutorial we wrote our first Acceptance Test for an Ember.js Application.

The process of Test Driven Developments is, write a test, watch it fail, then write just enough code to make it pass.

In today’s tutorial we will continue to see how we can write tests to drive the development of the application.

Iterating through a list of tasks

Last week we wrote a test to pull the number of open tasks from the DOM.

The easiest way of doing this is to simply hard code the tasks in the HTML.

However, in the real world we’re going to want to pull the tasks from an API.

So the first thing we need to do is to update the template file tasks.hbs under the app/templates directory:

<section>
  <ul class="task-list">
    {{#each task in open}}
    <li class="task"></li>
    {{/each}}
  </ul>
</section>

Now if you run the tests again you will see the acceptance test fails. This is because we’re trying to iterate through something that does not exist.

Creating a Controller

The test is failing because we’re trying to iterate through a property that does not exist. In order to make the test pass we need to create a new Controller:

ember g controller tasks

This command will create a new Controller file called tasks.js under the controllers directory:

import Ember from "ember";

export default Ember.Controller.extend({});

To make the test pass we can add the open property to the Controller and ensure that it returns an array of 3 items:

import Ember from "ember";

export default Ember.Controller.extend({
  open: function () {
    return [1, 2, 3];
  }.property(),
});

In the code above we are defining a function that will return an array of items. By adding the property() method to the end of the function we can use it as a property within the template.

Now if you run the tests again, everything should pass!

Adding a Model

Now that we are retrieving the data from the Controller we are moving in the right direction. However, returning an array of integers is not what we want, instead we need to return an array of Task objects.

Normally this would involve Ember Data to retrieve data from our JSON API.

However before we get into the complexity of Ember Data, our first step will be to create a simple Task object that extends Ember.Object.

The first thing I’m going to do is to update the test to pick the first task and then assert it has the correct text:

var task = find(".task-list .task:eq(0)");
assert.equal(task.text(), "Task 1");

This should make the test fail because currently we are only passing an array of integers to the template.

Next we can update the template to display the title attribute of the task:

<h2>Task List</h2>
<section>
  <ul class="task-list">
    {{#each task in open}}
    <li class="task">{{task.title}}</li>
    {{/each}}
  </ul>
</section>

For now we’re going to keep things simple and use a simple Ember.Object as the model. Create a new file called task.js under the models directory with the following code:

import Ember from "ember";

export default Ember.Object.extend({});

This is simply defining a new object that extends Ember.Object.

Finally update the Controller to look like this:

import Ember from "ember";
import Task from "helplist/models/task";

export default Ember.Controller.extend({
  open: function () {
    var one = Task.create({ title: "Task 1" });
    var two = Task.create({ title: "Task 2" });
    var three = Task.create({ title: "Task 3" });
    var four = Task.create({ title: "Task 4" });
    var five = Task.create({ title: "Task 5" });
    return [one, two, three, four, five];
  }.property(),
});

Now instead of returning a simple array of integers we are returning an array of Task objects.

Now if you run the tests again, everything should pass.

Conclusion

In today’s tutorial we move from a hardcoded template to getting data dynamically from the controller.

We also created a simple Ember.Object to represent the Task model.

And we updated the template to display an attribute of the model.

We are incrementally moving towards a dynamic, server based application.

Next week we will be introduction Ember Data and mocking the API server.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.