Back to Course |
Vue Inertia + Laravel 11: From Scratch

Form Validation and Multi-Submit Prevention

Our form doesn't have validation, so let's add it in this lesson.


Back-End Validation

First, let's add the validation on the back-end. For this, we will use Form Request.

php artisan make:request StorePostRequest

app/Http/Requests/StorePostRequest.php:

class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
 
public function rules(): array
{
return [
'title' => 'required|min:3',
'content' => 'required',
];
}
}

app/Http/Controllers/PostController.php:

use App\Http\Requests\StorePostRequest;
 
class PostController extends Controller
{
// ...
 
public function store(Request $request): RedirectResponse
public function store(StorePostRequest $request): RedirectResponse
{
Post::create([
'title' => $request->title,
'content' => $request->content,
]);
Post::create($request->validated());
 
return redirect()->route('posts.index');
}
}

We don't need anything else on the back-end.


Showing Errors on the Front-End

For the front-end, there are a couple of ways to get errors. One way is to get errors from the form helper.

resources/js/Posts/Create.vue:

// ...
 
<template>
<Head title="New Post" />
 
<AppLayout>
<form @submit.prevent="form.post(route('posts.store'))">
<div>
<div>
<label for="title" class="block text-sm font-medium text-gray-700">
Title
</label>
<input v-model="form.title" type="text" id="title" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
<p class="mt-2 text-sm text-red-600" v-show="form.errors.title">
{{ form.errors.title }}
</p>
</div>
 
<div class="mt-4">
<label for="content" class="block text-sm font-medium text-gray-700">
Content
</label>
<textarea v-model="form.content" id="content" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"></textarea>
<p class="mt-2 text-sm text-red-600" v-show="form.errors.content">
{{ form.errors.content }}
</p>
</div>
</div>
 
<div class="py-4 space-x-2">
<button type="submit" class="inline-block rounded-md bg-blue-500 px-4 py-3 text-xs font-semibold uppercase tracking-widest text-white shadow-sm">
Save post
</button>
<Link :href="route('posts.index')" class="inline-block rounded-md border border-gray-300 px-4 py-3 text-xs font-semibold uppercase tracking-widest shadow-sm">
Cancel
</Link>
</div>
</form>
</AppLayout>
</template>

It's that simple. We can see the validation message in the front-end.


Multi-Submit Prevention

Another feature of the Inertia form helper is that we can easily disable the submit button to prevent multiple submits.

If the back-end takes a while to process the form, you can disable the button. Form helper have a processing method.

resources/js/Pages/Posts/Create.vue:

// ...
 
<template>
<Head title="New Post" />
 
<AppLayout>
<form @submit.prevent="form.post(route('posts.store'))">
// ...
 
<div class="py-4 space-x-2">
<button type="submit" class="inline-block rounded-md bg-blue-500 px-4 py-3 text-xs font-semibold uppercase tracking-widest text-white shadow-sm">
<button type="submit" :disabled="form.processing" class="inline-block rounded-md bg-blue-500 px-4 py-3 text-xs font-semibold uppercase tracking-widest text-white shadow-sm disabled:opacity-25">
Save post
</button>
<Link :href="route('posts.index')" class="inline-block rounded-md border border-gray-300 px-4 py-3 text-xs font-semibold uppercase tracking-widest shadow-sm">
Cancel
</Link>
</div>
</form>
</AppLayout>
</template>

For example, we could add sleep in the Controller to make the request longer.

app/Http/Controllers/PostController.php:

class PostController extends Controller
{
// ...
 
public function store(StorePostRequest $request): RedirectResponse
{
sleep(2);
Post::create($request->validated());
 
return redirect()->route('posts.index');
}
}

After pressing the Save post button, you cannot click it again.