Search code examples
phplaravellaravel-5laravel-request

Split Laravel request errors into sections


I'm wanting to be able to split my laravel error messaged into sections.

Lets say I have an insurance policy page that has 3 sections

Driver Details

Car Details

Policy Details

I'm using a laravel request like this

'driver_name' => 'required',
'address_line_1' => 'required',
'address_line_2' => 'required',
'address_line_3' => 'required',
'postcode' => 'required',

I want to be able to tag certain input errors when validating with an input request like this so that I can display an error message at the top of each section, instead of 1 giant error block with all the errors in it.

In the request, how would i send it back with a section tag like

'driver_name' => 'required|section:driverDetails'

To split the errors?

If laravel error messages cant be tagged, what would be the best practise to achieve this?


Solution

  • You can use Vue.js and axios to validate and display the errors. Have a route called /validate-data in a controller to validate the data.

    app.js file:

           import Vue           from 'vue'
            window.Vue = require('vue');
            window.axios = require('axios');
    
            window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    
            let token = document.head.querySelector('meta[name="csrf-token"]');
    
            if (token) {
                window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
            } else {
                console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
            }
    
                 class Errors {
                    constructor() {
                        this.errors = {};
                    }
    
                    get(field) {
                        if (this.errors[field]) {
    
                            return this.errors[field][0];
                        }
                    }
    
                    record(errors) {
                        this.errors = errors;
                    }
    
                    clear(field) {
                        delete this.errors[field];
                    }
    
                    has(field) {
                        return this.errors.hasOwnProperty(field);
                    }
    
                    any() {
                        return Object.keys(this.errors).length > 0;
                    }
                }
    
                new Vue({
                 el: '#app',
    
                    data:{
                   errors: new Errors(),
                  model: {
        driver_name: '',
        address_line1: '',
        address_line2: ''
        },
                },
    
            methods: {
              onComplete: function(){
                  axios.post('/validate-data', this.$data.model)
                      // .then(this.onSuccess)
                      .catch(error => this.errors.record(error.response.data.errors));
               },
    }
            });
    

    Make a route called /validate-data with a method in the controller, do a standard validate

    $this->validate(request(), [
    'driver_name' => 'required',
    'address_line_1' => 'required',
    'address_line_2' => 'required',
    'address_line_3' => 'required',
    'postcode' => 'required'
    ]
    

    Then create your inputs in your view file, using v-model that corresponds to the vue.js data model fields. Underneath it, add a span with an error class (basic red error styling, for example) that only shows up if the errors exist. For example:

    <input type="text" name="driver_name" v-model="model.driver_name" class="input">
    <span class="error-text" v-if="errors.has('driver_name')" v-text="errors.get('driver_name')"></span>
    

    Don't forget to include the app.js file in footer of your view file. Remember to include the tag, and run npm run watch to compile the vue code. This will allow you to validate all errors underneath their input fields.

    Forgot to add, have a buttton that has @onclick="onComplete" to run the validate method.