Aug 03, 2015
Table of contents:
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.
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
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!
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.
The process of validating the new task object will be as follows.
Task
object as normal. 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.
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!
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.