This tutorial is out of date and no longer maintained.
In this post, I will be showing you how to handle Laravel validation error messages with Vue.js.
Recently, I launched an open-source side project I was working on called Open Laravel. Open Laravel allows developers to submit open-source projects that were built using the Laravel framework. The project submission page uses Vue.js to submit the form asynchronously through an AJAX
request. Since I am no longer sending the form the default way (refreshing after form submission), I needed a way to show Laravel form validation error messages. After going back and forth with some forum questions and answers, I was able to make it work.
How I solved this is what I’ll be showing you in this tutorial. A quick demo is shown below.
I’ll be using a basic post-creation demo for this tutorial. I’ll start with a fresh installation of Laravel. I named the demo vuejs-laravel-validation-error-messages
, feel free to name it whatever you like.
- laravel new vuejs-laravel-validation-error-messages
For this tutorial, we’ll be making use of Laravel Elixir
. Laravel Elixir is a tool that allows you to perform Gulp tasks inside your Laravel applications.
More on it can be found on Laravel Elixir. We’ll be using Laravel Elixir to build and compile the JavaScript we will be writing. So before anything, we need to install Laravel Elixir dependencies:
- npm install
Having installed Laravel Elixir dependencies, it’s time to define and install the project dependencies. We’ll be making use of the following:
We need Vue.js
as indicated in the tutorial title. vue-resource
which is an HTTP client for Vue.js making web requests and handling responses using XMLHttpRequest or JSONP. And lastly laravel-elixir-vueify
is a wrapper for Laravel Elixir and the Browserify Vueify plugin which allows you to write your templates
, scripts
and styles
all in one .vue
file. Install each of the dependencies using npm
. With the project dependencies installed, we can get to the meat of the project.
Open routes.php
and paste the code below into it
Route::post('create-post', 'PostsController@save');
Create a PostsController
that will handle the logic for our post creation demo.
- php artisan make:controller PostsController
Add a save()
to the PostsController
public function save(Request $request)
{
// set form validation rules
$this->validate($request, [
'title' => 'required',
'body' => 'required'
]);
// if the validation passes, save to database and redirect
}
The save()
handles post creation form validation.
For the purpose of the tutorial, I’m keeping the validation simple by only making both the title
and body
fields required.
Create a new file inside the views
directory and name it post.blade.php
. Paste the code below in it.
<!DOCTYPE html>
<html>
<head>
// add csrf token
<meta id="token" name="token" value="{{ csrf_token() }}">
<title>Handling Laravel Validation Error Messages With Vue.js</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css">
<style>
body {
padding: 50px;
}
</style>
</head>
<body>
<div class="container">
// this will be displayed upon successful submission of form
<div class="alert alert-success" v-if="submitted">
Post created!
</div>
// prevent the page from refreshing after submission
<form @submit.prevent="createPost" method="POST">
<legend>Create Post</legend>
// add Bootstrap .has-error if title field has errors
<div class="form-group@{{ errors.title ? ' has-error' : '' }}">
<label>Post Title</label>
<input type="text" name="title" class="form-control" v-model="post.title" value="{{ old('title') }}">
// display errors if field has errors using FormError component
<form-error v-if="errors.title" :errors="errors">
@{{ errors.title }}
</form-error>
</div>
// add Bootstrap .has-error if body field has errors
<div class="form-group@{{ errors.body ? ' has-error' : '' }}">
<label>Post Body</label>
<textarea name="body" class="form-control" rows="5" v-model="post.body">{{ old('body') }}</textarea>
// display errors if field has errors using FormError component
<form-error v-if="errors.body" :errors="errors">
@{{ errors.body }}
</form-error>
</div>
<button type="submit" class="btn btn-primary">Create Post</button>
</form>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
You should have a form similar to the image below:
Again, a simple form. There is a success message that will be displayed upon submission of the form using v-if
.
Since we want the form to be submitted asynchronously (without page refresh), @submit.prevent
will prevent the page from refreshing after submission.
The form input data will be POST
ed to a createPost
function which we are yet to create. As you can see, I’m doing {{ errors.title ? ' has-error' : '' }}
which will add Bootstrap .has-error
if the title
field has errors. The same applies to the body
field.
To display the error messages when validation fails, I’m using the FormError
component (which we are yet to create) and passing to it errors
(which contains error messages) as props.
Create a new js
folder inside resources/assests
directory. Inside the newly created js
folder, create an app.js
file. Before going further, open the gulpfile.js
file and update it with:
var elixir = require('laravel-elixir');
require('laravel-elixir-vueify');
elixir(function(mix) {
mix.browserify('app.js');
});
Notice above, where we require laravel-elixir-vueify
, which will compile our .vue
file when we run gulp
.
In the resources/assests/js/app.js
file, paste the code below into it.
import Vue from 'vue';
import VueResource from 'vue-resource';
// tell Vue to use the vue-resource plugin
Vue.use(VueResource);
// import FormError component
import FormError from './components/FormError.vue';
// get csrf token
Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('value');
// instantiate a new Vue instance
new Vue({
// mount Vue to .container
el: '.container',
// define components
components: {
FormError,
},
data: {
post: {
title: '',
body: '',
},
submitted: false,
// array to hold form errors
errors: [],
},
methods: {
createPost() {
let post = this.post;
this.$http.post('create-post', post).then(function(response) {
// form submission successful, reset post data and set submitted to true
this.post = {
title: '',
body: '',
};
// clear previous form errors
this.$set('errors', '');
this.submitted = true;
}, function (response) {
// form submission failed, pass form errors to errors array
this.$set('errors', response.data);
});
}
}
});
First, we import the packages (vue
and vue-resource
) installed earlier and tell Vue.js to use the vue-resource
plugin. Also, we import FormError
component which we’ll create shortly.
Next, we create a Vue
instance and pass it an options object. The el
tells Vue.js
the element to mount on. The components
object accepts any components (FormError
in our case) we want to be included in our Vue
instance. The data
object contains data that can be rendered in a view. The post object contains a title and body object. It will hold the created post and will be bound to the post creation input fields. The submitted
defaults to false will be used to show the success message upon submission of the form. The errors
array will obviously hold the errors messages returned during form validation. Finally the methods
object contains a single createPost()
.
Taking a closer look at the createPost()
, first, we declare a variable post
to hold the post data (submitted form data since we have two-way binding). Next, we send a post request to the route create-post
using the post()
of vue-resource
plugin passing along the post variable (which now holds the submitted form data). If the request was successful, we set the form input value to an empty string and set submitted
to true to show the success message. But if the request was not successful (that is the form validation failed), we set the errors
array to hold the form validation error messages Laravel sends upon failed validation.
The FormError
component is going to be a very simple component. Create a new components
folder in resources/assests/js
and create a new file FormError.vue
inside the newly created components
folder. Paste the snippets below into it
<template>
<span class="help-block">
// this will be replaced by the error messages
<slot></slot>
</span>
</template>
<script>
export default {
props: ['errors'],
}
</script>
The template is a simple Bootstrap help block. The <slot>
tag will allow us to pass dynamic content into the template. In our case, the <slot>
will be replaced by the error messages. Since the form validation error messages are unique to each form field, having the template show a specific error message for each field makes sense. The FormError
component accepts a props
errors
which must be passed along to the template.
Now if you submit the form without filling the appropriate fields, you will get something similar to the image below showing the error messages:
But if you fill the form as appropriate, you should get something like below:
That’s it. I hope you find this tutorial useful. If you encounter any problems following this tutorial or have suggestions, kindly drop them in the comment below.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.