cult3

Creating new Ember Data objects

Jul 27, 2015

Table of contents:

  1. How this is going to work
  2. Adding the route
  3. Adding the form
  4. Adding the form template
  5. Creating Controller
  6. Conclusion

In last week’s tutorial we looked at transitioning to view an individual task. This involved writing a failing test and then incrementally implementing the functionality to make the test pass.

So far in this mini-series we’ve created a task list, added task replies, and looked at viewing individual tasks.

In today’s tutorial we will look at creating a new Task and how we can implement this functionality using Test Driven Development.

How this is going to work

Creating a new Task is going to be a two-step process.

First we need to add a new route tasks/new that will present a form to the user. This form will allow the user to submit their task.

When the user submits the new task, the Ember application should make a POST request to the API.

This form will also need validation, but we can worry about that next week.

Adding the route

To begin implementing this functionality, first I will generate a new acceptance test:

ember g acceptance-test new

Next I will add a test to assert that visiting the tasks/new page works as it should:

test("visiting /tasks/new", function (assert) {
  visit("/tasks/new");

  andThen(function () {
    assert.equal(currentURL(), "/tasks/new");
  });
});

If you run this test now, you should see it fail.

In order to make this test pass we need to add a new route to the router:

import Ember from "ember";
import config from "./config/environment";

var Router = Ember.Router.extend({
  location: config.locationType,
});

export default Router.map(function () {
  this.route("tasks", { path: "/" });
  this.route("new", { path: "/tasks/new" });
  this.route("task", { path: "/tasks/:task_id" });
});

Adding the form

Now that the new route is in place we can add a test that will submit the form. When the form is submitted we should be redirected to view the task that was just created:

test("create new task", function (assert) {
  visit("/tasks/new");

  andThen(function () {
    fillIn(".task-title", "Hello world");
    click("button");
  });

  andThen(function () {
    assert.equal(currentURL(), "/tasks/1");
  });
});

In this test we first go to the new task URL:

visit("/tasks/new");

Next we fill in the form and click the submit button:

andThen(function () {
  fillIn(".task-title", "Hello world");
  click("button");
});

Next we assert that we have been redirected to view the new task:

andThen(function () {
  assert.equal(currentURL(), "/tasks/1");
});

Once again, if you run this test now you should see it fail.

Adding the form template

So the first thing we need to do to make this test pass is to actually provide the user with the form to submit. We can do this by creating a new new.hbs template and adding the form HTML:

<form>
  <label for="'title'">Title</label>
  {{input value=title class="task-title"}}

  <button type="submit">Save</button>
</form>

In the chunk of code above I’m using Ember’s input tag helper. If you’re unfamiliar with how Ember deals with templates, take a look at Using Templates in Ember. If you fire this up in the browser and try submitting the form nothing will happen. In order to tell Ember to do something when the form is submitted we need to add an action to the form:

<form {{action "createTask" on="submit"}}>

This will call the createTask handler when the form is submitted.

Now if you try submitting the form again you will see an error in the console relating to nothing handling the action.

If you remember back to Using Controllers in Ember, you will know that it is the responsibility of the Controller to handle these types of actions.

Creating Controller

To create a new Controller we can use Ember’s generators:

ember g controller new

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

import Ember from "ember";

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

Inside of the Controller we can add an actions block and a createTask function that will be called when the form is submitted.

import Ember from "ember";

export default Ember.Controller.extend({
  actions: {
    createTask: function () {},
  },
});

To test this out we can pop an alert.

export default Ember.Controller.extend({
  actions: {
    createTask: function () {
      alert("Hello world");
    },
  },
});

Now if you submit the form you should see the alert box.

To create a new Task we can call the createRecord method on this.store. We covered creating new records with Ember Data in Working with Records in Ember Data:

var task = this.store.createRecord("task", {
  title: this.get("title"),
});

This will create the new Ember Data object, but we also need to make a POST request to /api/tasks.

To do this we can call the save() method on the Ember Data instance and pass callbacks for success and failure.

If the request is successful we can redirect to view the newly created task:

task
  .save()
  .then(function (task) {
    self.transitionToRoute("task", task);
  })
  .catch(function () {
    alert("Oh no! :(");
  });

If the request is unsuccessful we can just pop an alert box. In the real world you would actually want to deal with this error.

Finally we need to add the POST route to the Mirage config.js file:

this.post("/api/tasks");

Now if you run the tests again you should see it pass.

Conclusion

As with last week’s tutorial, we haven’t had to do a great deal to get this working. Ember already provides a lot of the building blocks you will need to do a lot of the main plumbing of an application.

In this tutorial we’ve looked at wiring up a form to a controller, creating a new Ember Data object and then sending the POST request to the API.

If you were writing this from scratch, it would take a long time to bootstrap all of this functionality, but with Ember it will take you less than 10 minutes.

That really is the beauty of using a framework like Ember.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.