cult3

Adding Validation to Ember Forms

Aug 03, 2015

Table of contents:

  1. Adding the Ember Validation addon
  2. Writing the test
  3. Add the validation to the Controller
  4. Validate on save
  5. Add errors to form
  6. Conclusion

Last week we looked at creating a new task in an Ember application.

This involves accepting data from the form, creating a new task in Ember Data, and then saving the task, which will send a POST request to the server.

A good API will validate incoming data to ensure that it is of the correct format. This will typically involve the API sending back the correct HTTP status code and a helpful message describing why the input was incorrect.

However, we can try to prevent the request ever hitting the API server by also doing validation in the client.

In today’s tutorial we will be looking at validation to Ember forms.

Adding the Ember Validation addon

Validation is like the canonical use case of Open Source Software. You should never have to write validation code because there’s always an open source solution waiting to be pulled into your project.

A good Ember addon is the Ember Validation package. This is what we’ll be using in this tutorial.

To add addon to your project you can add the following line to your package.json file:

"ember-validations": "2.0.0-alpha.3"

At the time of me writing this, 2.0.0-alpha.3 is the latest release.

Next run the following command to install the package:

npm install

Writing the test

The first thing we need to do is to write a test that will show the functionality we intend to build:

test('validate task data', function(assert) {
    visit('/tasks/new');

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

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

As you can see, this test is fairly similar to the test we wrote last week for adding a new task. However, in this task we want to assert that the user is returned to the /tasks/new URL when the task title is blank.

If you run this test now you should see it fail because the user will be redirected to tasks/1.

With the test in place, we can write the code to make it pass!

Add the validation to the Controller

To make the test pass we need to run a validation process at some point during the request execution that will check to ensure the task title is not blank.

Typically I think this is probably best handled in the model because the requirement of a task title is the concern of the model.

However, I’m not entirely sure how to do that with this addon, so validation in the Controller will do fine for now.

To add the validation functionality to our Controller from last week we can include it as a mixin:

import Ember from "ember";
import EmberValidations from "ember-validations";

export default Ember.Controller.extend(EmberValidations.Mixin, {});

Next we can add a displayErrors flag property. This will be used for displaying the errors in the template:

displayErrors: false,

And finally we will also add a validations object that will contain the validation rules.

validations: {
    title: { presence: true }
},

In this case we only have a single rule.

Validate on save

The process of validating the new task object will be as follows.

  1. We will create the Task object as normal.
  2. Next we will validate the object
  3. If the object is valid we can call the save method and redirect to view the new task
  4. If the task is not valid we can flip the displayErrors flag which will display the errors in the template

This process looks like this in code:

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

    var self = this;

    this.validate().then(function() {
        if (self.get('isValid')) {
            task.save().then(function(task) {
                self.transitionToRoute('task', task);
            }).catch(function() {
                alert('Oh no! :(');
            });
        }
        }, function() {
            self.set('displayErrors', true);
        }
    });
}

Note, we’re validating the Controller data, not the model object itself, but you get the point.

Add errors to form

Finally we can add the errors to the template. First we check to see if the displayErrors flag is true. We only want to display the errors if this flag is set to true:

{{#if displayErrors}} {{/if}}

Next we iterate through the errors array:

{{#if displayErrors}} {{#each errors.title as |error|}}
    <div>{{error}}</div>
{{/each}} {{/if}}

Now if you run the tests again, you should see them all pass!

Conclusion

Validation is never something you want to write yourself. Every language and every framework already has a validation library.

Adding validation to an Ember project isn’t hard. We’ve added the validation to the controller and to the form with only a couple of lines.

Of course, in a real project, your validation requirements would probably be a lot more complicated. We also really should deal with the server sending us validation problems.

The server will really be your one true source and so your ember application should be prepared to accept validation responses and treat them in the same way as client response.

If you don’t do this, your application will be very annoying to use for the end user.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.