Next lesson playing in 5 seconds

  • Overview
  • Transcript

2.5 Improving Invalid Forms

Client-side validation is great, but we also want to provide visual cues to further enhance the user's experience. We'll use one of Vue.js's features to conditionally change the way invalid form fields look.

2.5 Improving Invalid Forms

In the previous lesson, we added the V Validate package to our project so that we could use that to validate our form. And it was very easy to add and use. However, there's some things that I want to address. For one, If we have an invalid form, we are still allowed to submit that form. And in some cases we might want that, but in this case I don't. So I want to prevent form submission if the form is invalid. The other thing I want to address is to add more visual cues that something is wrong. I mean, it is nice that there is a message, and the message could arguably be enough. But I want to add some more visual cues. And since we're using Bootstrap, we have a lot of tools available to us. And one of those is the CSS class called has-error. And we can add this to the div element with a class of form-group. So if I quickly do that, what we see then is a red border around the field that would have an error. And I want to add that functionality. So let's start with that, because that's very easy to do. What we want to do then is, for everyone of these div elements that has a class of form-group that contains a field that's going to be validated we want to add that has-error class if there's an error, otherwise we don't want it there. Well we already have the class attribute, and you might think that we could come in here and use our mustaches and then say errors.has, and then title and so on and so forth. And that would be a good idea, except that we cannot use mustaches inside of HTML attributes. So instead what we're going to do is bind CSS classes to these elements. And we do so with the same binding syntax that we've used thus far. We simply say :class, and then inside of the value for this attribute is going to be what is essentially a JavaScript object. The properties of this object are going to be the CSS classes that we may or may not want to apply to the element. So in this case the CSS class is has-error. And then the value is going to be either true or false depending upon if we want that class to be applied to the element. So in this case all we need to do then is say errors.has('title'). And so if we have an error for the title field then that has-error class is going to be applied to that div element. So if we refresh the page. And if we force the validation to take place, we can see that indeed that class is being added to the element. So this might look a little strange considering that we have the HTML attribute of class and then we have the view binding class attribute, but this is typically how we fix this. So let's just copy and paste this and make the necessary changes so that we are referencing the correct field. So we have the URL, and then farther down we have the content. Let's see, there it is. And we are done with that. Now we want to prevent the form submission in case of an invalid form. Of course, this means that we need to either handle the form submit event, or we need to handle the click event of the button. Now, the way that this component is currently set up, we don't have access to the form element itself. Ideally we would have the entire form here inside of the component. And that is probably something that we will eventually have, but for right now we don't. So our only option then is to handle the click event for the button. And we can do that very, very easily by doing this. We're going to say @click, and then we specify a method name. Now we don't have this method, but we're going to write it. Let's just call it validateBeforeSubmit, and then we will add this method to our methods down here in our script. And we will accept the event object. And then all we need to do is check to see if we have some errors. And if we do, then we don't submit the form. And we do that by saying this.$validator. Now the dollar sign is just a convention. It's there to prevent naming collisions. And it typically means that this is a publicly available API. So it is not like this is hidden feature. This is just how we access the validator object. And so we say this.$validator, and it has a method called validateAll, which as its name implies is going to validate all of the validators on the form. And this is an asynchronous method, so we need to call then, and it's going to give us a result. If everything is okay with the form then result is going to be true. If not then an error occurred, and so that is what we want to check for. And then we simply say preventDefault(). Now we have successfully prevented the form from being submitted for an invalid form. So let's just refresh the page and test it out. If we have an invalid form and we try to submit, of course, nothing is going to happen whenever we submit. And that's the behavior that I wanted. Now if you start playing around with this, you're going to see some rather strange things. Like for example, let's put our focus on Title and just press a key. It doesn't matter what key it is as long it is alphanumeric. So I'm going to type the letter t. Now notice that nothing happened except that the validation error went away. And if we type anything else again, then we start to see the text up here. However, if I press tab to go to the next field URL and I start typing here. I'm going to type a slash. We can see that the title went away and the arrow went away for the URL. What in the world is going on here? Well, whenever we initially set this up we used the value. More specifically, we said a v-bind value. And we bound the value to the title and to the URL. And while that's technically not incorrect, because we haven't noticed an issue until we started working with validation. It is going to be a problem now that we have added validation. Because what we have done is we have bound these values to the value of the input element. And so now any time that these fields are validated, they are going to reset back to their initial value. So because we have a model that has an empty string for the title and the URL, those are the values of these fields. If we go and edit one of our existing pages and we try to clear out one of these values. You can see that it just keeps resetting over and over and over again. So binding to the element's value is not going to work in this case. Instead what we need to do is set these to v-model. So let's go ahead and do that. Because if we look at the content, which is a text area, which we did use v-model on, you'll see that we don't run into any of the issues that we have with the title of the URL. So if we set v-model equal to our title and our URL, then everything is going to be fine. And the issue here is that by binding everything to the value we set up what was essentially a one way binding, whereas the v-model is a two way binding. So now let's refresh the page, we can clear out any field that we need to. And if we go to the Create New form and we have an invalid field marked, whenever we start typing, I'm going to type T, we can see that we immediately see something. Whereas before it would just clear the error and we didn't see anything in the field. So we could say this is a page. And then for the URL we can see that nothing clears out of the title, and everything behaves as it should. And so now that we've made a few improvements to our form, we need to do one other thing as far as the validation is concerned. And that is validating the URL, because the URL needs to be unique. And that uniqueness is enforced by the database. However, it would be nice to check to see if the URL is available before the user submits the form. And we will do that in the next lesson.

Back to the top