Displaying Server Side Errors along inputs

.then() and .catch()

We need to add .then() and .catch() to handle success and errors respectively.

sendmail() {

let fd = this.appendFormData();

axios.post('api/mail', fd)

.then(response => console.log(response))

.catch(error => console.log(error))

},

Sending an empty form will show us an error in the console like this:

If we read the axios documentation 🔍, we find a section called Handling Errors . It shows us that the error response data is at error.response.data

Let’s log the error response data

sendmail() {

let fd = this.appendFormData();

axios.post('api/mail', fd)

.then(response => console.log(response))

.catch(error => console.log(error.response.data))

},

In the console, we find that error.response.data has an object called errors and a property called message.

What we need is the errors object and we need it to appear in data().

Putting error data in data()

In data(), we need an object for storing the caught errors

data() {

return {

form: {

name: '',

email: '',

message: '',

},

LVErrors: {

}

}

},

We need to change the .catch() code so that the errors appear in the LVErrors data() return object

sendmail() {

let fd = this.appendFormData();

axios.post('api/mail', fd)

.then(response => console.log(response))

.catch(error => this.LVErrors = error.response.data)

},

If we submit an empty form and use Vue DevTools, we can see the following:

Errors are in the errors object and we don’t need the message property, so let’s change the .catch() code to have only the errors object in this.LVErrors

.catch(error => this.LVErrors = error.response.data.errors)

Now we submit an empty form and we see something similar but different.

We can now render error messages by using double curly brackets {{ }}. If we use a span element our code is going to be something like:

<span>{{ LVErrors.name }}</span> (to render the name error).

Let’s test it out below the name label.

<label for="name">Name</label>

<span>{{LVErrors.name}}</span>

<input type="text" placeholder="name" id="name" v-model="form.name"/>

Upon submiting an empty form, now we get:

{{LVErrors.name}} renders [ “The name field is required.” ] because {{LVErrors.name}} contains an array, in which is the message string at index 0.

We have three approaches to solve this:

Index number in curly braces {{ }} Empty property in the data() return{}’s LVErrors object Vue.set

1. Index number in curly braces {{ }}

To render the error without the array brackets [], we can add [0] to {{LVErrors.name}} so it becomes {{LVErrors.name[0]}} .

Now we will have this:

<label for="name">Name</label>

<span>{{LVErrors.name[0]}}</span>

<input type="text" placeholder="name" id="name" v-model="form.name"/>

We may get the following error:

“TypeError: _vm.LVErrors.name is undefined”

This error occurs because we are asking for index [0] of LVErrors.name and LVErrors.name does not exist at the time of loading the page. Vue expects an object to exist before we can look at the object’s indexes.

To solve this issue, we can make the appearance of {{ LVErrors.name[0] }} conditional by using v-if:

<span v-if="LVErrors.name">{{LVErrors.name[0]}}</span>

Now the error message will appear on the page (without the square brackets) on the condition that LVErrors.name in data() return {} exits beforehand.

2. Empty property in the data() return{}’s LVErrors object

The second approach to combat the issue of messages appearing in the manner of [ “MESSAGE HERE” ] is to create the property in data() return {} yourself and set it to an empty string.

So instead of using v-if, you could just put name in data() return {} like this:

LVErrors: {

'name' : ''

},

And we can have the errors without v-if

<span>{{LVErrors.name[0]}}</span>

We will see an empty span in inspect element when we load the page and DON’T submit the form:

If we load the page and DO submit the form:

NOTE: INSPECT ELEMENT/DEVTOOLS SHOULD BE USED AFTER SUBMITTING THE FORM OTHERWISE WE NOT SEE THE MESSAGES IN THE SPAN ELEMENT

The third approach is to use Vue.set. Let’s look at Vue.set

3. Vue.set

Vue.set is a built in Vue function that allows you to populate an object with a key and value. Here is an example:

You have an object called banana like this:

data() {

return {

banana: {



}

}

},

And you have this method:

addColor() {

Vue.set(this.banana, 'color', 'banana');

}

Upon page load, Vue Devtools will show an empty Object called banana like so:

And when you use the Vue.set method, you will find that the Object banana has been populated with a propertyName and value. The propertyName is color and the value is yellow:

NOTE: You may need to click the REFRESH button to see the data change in Vue Devtools.

If you want to see the data change live, you can just have {{ banana }} in the template element.

Now that we understand Vue.set, let’s see how we can use it for our purpose

How we can use Vue.set

Our purpose is to populate LVErrors with the error messages found in error.response.data.errors

To use Vue.set, we have to follow the following syntax:

Vue.set( target, propertyName, value )

Our target is LVErrors .

is . The propertyName we want is the error name .

we want is the . The value we want is the error message.

Now the question is “where can we get the propertyNames and values from?”

We know that the propertyNames can be found in the received object (error.response.data.errors)

AND

We know that the values are at index 0 of every item.

Since there are multiple errors that have to be set, we should use a for in loop in .catch() like so:

.catch(error => {

let errors = error.response.data.errors;

for (const item in errors) {

Vue.set(this.LVErrors, item, errors[item][0])

}

});

Now for every item in the errors object, the item name and value will be set.

And now we can make all the errors appear alongside our inputs by having code like this:

<label for="name">Name</label>

<span>{{LVErrors.name}}</span>

<input type="text" placeholder="name" id="name" v-model="form.name"/>

<label for="email">Email</label>

<span>{{LVErrors.email}}</span>

<input type="text" placeholder="email" id="email" v-model="form.email"/>

<label for="message">Message</label>

<span>{{LVErrors.message}}</span>

<input type="text" placeholder="message" id="message" v-model="form.message"/>

<input type="submit" @click.prevent="sendmail"/>

Now upon form submission, you’ll have something that looks like this:

Now it’s time to move onto hiding the errors if their respective input boxes have text in them or not.

But before that let’s give the errors some styling

<span class="error">{{LVErrors.name}}</span>