Tutorial

Handling Laravel Validation Error Messages With Vue.js

Draft updated on Invalid Date
Default avatar

By Chimezie Enyinnaya

Handling Laravel Validation Error Messages With Vue.js

This tutorial is out of date and no longer maintained.

Introduction

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.

Let’s Begin

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.

  1. 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:

  1. npm install

Project Dependencies

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.

The Routes

Open routes.php and paste the code below into it

routes.php
Route::post('create-post', 'PostsController@save');

Posts Controller

Create a PostsController that will handle the logic for our post creation demo.

  1. php artisan make:controller PostsController

Add a save() to the PostsController

PostsController.php
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.

Post View

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 POSTed 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.

Vue.js File

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:

gulpfile.js
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.

resources/assests/js/app.js
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.

FormError Component

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:

Conclusion

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.

Learn more about us


About the authors
Default avatar
Chimezie Enyinnaya

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


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!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel