Search code examples
phplaravellaravel-8inertiajs

How to make form validation in InertiaJS with Formhelper


Setup: Laravel 8 + Inertia JS with Vue 3

I'm trying to implement inline form.errors with InertiaJS like desribed here: https://inertiajs.com/forms#form-helper

But that doesn't work. All form-helpers like form.processing are available but not form.errors.

Firstly I am sharing the errors from Laravel via boot() in AppServiceProvider.php

AppServiceProvider.php

public function boot()
    {
        Inertia::share([
            'errors' => function () {
                return Session::get('errors')
                    ? Session::get('errors')->getBag('default')->getMessages()
                    : (object) [];
            },
        ]);

        Inertia::share('flash', function () {
            return [
                'message' => Session::get('message'),
            ];
        });
    }

Secondly I setup the Vue-File with the InertiaJS form helper. If I write instead of "form.errors.asin" -> "$attrs.errors.asin" the error will be displayed, but not within the form-Object and I don't know why is that.

Index.vue

<template>
  <main>
    <form @submit.prevent="submit">
        <div v-if="form.errors.asin">{{ form.errors.asin }}</div>
        <input id="asin" v-model="form.asin" label="ASIN:" />
        <button disabled="form.processing" type="submit"> Translate </button>
    </form>
  </main>
</template>

<script>
import { useForm } from "@inertiajs/inertia-vue3";

export default {
  setup() {
    const form = useForm({
      asin: null,
    });

    return { form };
  },
  methods: {
    submit() {
      this.form.get(
        "/translation/translate",
      );
    },
  },
};
</script>

HandleInertiaRequests.php

public function share(Request $request)
    {
        // In parent::share the error $attrs are shared
        return array_merge(parent::share($request), [
            'appName' => config('app.name'),
            'auth' => [
                'user' => $request->user()->only('id', 'email', 'is_admin', 'name'),
            ],
            'flash' => [
                'message' => function () use ($request) {
                    return [
                        'success' => $request->session()->get('success'),
                        'error' => $request->session()->get('error'),
                    ];
                }
            ],
        ]);
    }

As you see in the picture, the error is set under $attrs.errors.asin but not under form.errors

Vue Debug Tools


Solution

  • The frontend part of inertia has different expectations regarding the errors.

    You could:

    a) grab the exact part you need from here or

    b) remove everything under AppServiceProvider@boot and create a new middleware extending Inertia's middleware - this will serve as a place to share all your additional props (the flash prop for example).

    <?php
    
    namespace App\Http\Middleware;
    
    use Illuminate\Http\Request;
    use Inertia\Middleware;
    
    class HandleInertiaRequests extends Middleware
    {
        protected $rootView = 'app';
    
        public function version(Request $request)
        {
            return parent::version($request);
        }
    
        public function share(Request $request)
        {
            return array_merge(parent::share($request), [
                //
            ]);
        }
    }
    

    The middleware needs to be applied on the web group inside app/Http/Kernel.php.