Series: Form Validations with ember-validations
Displaying Validation Errors
Published on Aug 14, 2015
Validation errors are far more useful if you can show them to your users.
In this screencast we look at two different strategies- flash messages and inline messages.
Links
- Check out emberscreencast episode 64
- ember-cli-flash episode
- GitHub diff for flash messages
- GitHub diff for inline messages
Code
Display errors in flash messages:
actions: {
save(){
//...
this.validate().then(()=>{
model.save().then(()=>{
this.transitionToRoute('post.show', model)
})
}).catch(()=>{
var errorHashes = this.get('errors.model')
var errorKeys = Object.keys(errorHashes)
this.get('flashMessages').clearMessages()
errorKeys.forEach((key)=>{
errorHashes[key].forEach((error)=>{
this.get("flashMessages").danger(`${key} ${error}`, {sticky: true})
})
})
console.log(this.get("errors"), errorKeys)
})
}
}
You can also display errors inline. Here's a display-errors
component you can use:
{{#if showErrors}}
{{#each errors as |error|}}
<p style="color: red;">{{error}}</p>
{{/each}}
{{/if}}
And here is it being used in a template:
<p>Title: {{input value=model.title}}</p>
{{display-errors errors=errors.model.title showErrors=showErrors}}
<p>Length (in seconds): {{input value=model.seconds}}</p>
{{display-errors errors=errors.model.seconds showErrors=showErrors}}
The showErrors attribute usually starts off false, but then is turned to true when validation fails.
Transcript
In the last episode, we used the ember-validations library in order to show errors on our forms. However, we didn’t actually show errors on our forms yet. We just caught the errors and showed them in a console.log
. In this episode, we’re going to be talking about how to display those validation errors. We’re going to be doing this in two ways. The first is through flash messages, and the second is through inline error messages.
So flash messages, in Episode 57 we learned how to use ember-cli-flash to show those, and we already have flashMessages
in the application template. What we need to do is in our controller, we take our errors
hash and we turn that into a series of flash messages that can show to the user. So to jog your memory, this is how flash messages work. First, you call to get flashMessages
, and then you add them by calling something like warning
or success
, or in this case, danger
, and then you send it a message. Now when we have an error, it’ll display a flash message.
However we’re going to want something more specific than that. We’re going to want to get it from the errors
. The errors
hash if you remember it from last time is a series of nested hashes, so it has model
. The model has several different properties, seconds
and title
in this case. And then it has errors
on each one where there are errors. In this case there are two errors on title
and none on seconds
.
So first we’ll get the various errorHashes
, and we’ll get that from the errors
hash going down to the model
, then we’ll pull the various keys
from it. In this case it’ll be title
and seconds
. Then we’ll loop through those keys and use that to pull the value out of the errorHashes
. Each value is an array of different messages, so we’ll loop through that. Then we’ll grab our flashMessages
array and we’ll add something that says key
and then the error
, so it’ll say something like 'title is not long enough'. Then we can removethis old flash message.
Let’s go ahead and look this in action. So we remove this 'Title', we’ll make this not a number, and it’s giving us these errors. But they go away really quickly, so let’s go ahead and make them sticky
, and since they’re sticky we’ll need to remove them every time. So we’ll run this again, it gives us these errors, and they can stay there. The user can make them go away by clicking on them.
So this works and it’s fairly easy, and you could theoretically create a method called like sendErrorsToFlash
and have that run wherever you want to have this type of action. It’s agnostic to what the errors actually are. However the user experience is not great. You see these errors and you have to go find them below, and in the case of seconds it looks like it’s called ‘Length’ even though it’s named ‘seconds’. So let’s try to find a way to put these in line.
So below each of the things where we have a validation, we’ll want some sort of component. We’ll call it display-errors
. And then we’ll pass it in errors
, and we’ll pass it in a boolean that says whether it will show the errors. So the errors in this case will be found on the errors hash, and then we’ll go into the model
and then title
, and then showErrors
will be appropriately named. Notice the correspondence here. So we’ll separate this out, and the value of this input is model.title
, and the errors are errors.model.title
.
So what would this display.errors
component look like? We would have an if
statement saying okay, we’re only going to show these if the showErrors
boolean is true. Then we’re going to loop through the errors and show all the errors in red. Then we’ll go ahead and create another display-errors
component for the other property that has a validation. And then notice that this is in the edit-fields
component so we’ll have to pass in the errors
hash and the showErrors
boolean to that component. So we’re back in the edit
controller, and let’s start off by having showErrors
equal to true
, and we’ll see how that affects it. So we can start deleting this and when it gets below 5, it’ll show that error, and when there’s nothing it’ll say can’t be blank
.
This is pretty good, so I’d say this is good for edit
, but why did we want to have that showErrors
boolean? So let’s go to our posts/new/template
, and when we’re calling the edit-fields
, we’ll put in showErrors
and errors
, and then we’ll go ahead here in the controller, set showErrors
to true
. Let’s see what happens there. This is basically repeating the work we did for the edit
controller. So we start off with all the errors showing, and that’s not great. So in our new posts controller, we’ll set showErrors
to false
automatically. And then once saving has failed, then we’ll set showErrors
to true
. When we go to our page, it doesn’t show any errors until we hit save, and that’s just the behavior we want.
So in this episode, we saw two different ways to show the error messages to the user. One was using flash messages and the other was to show them inline. Tune in next week as we talk more about validations, how to do more advanced validations than just length and presence. I’ll see you then.