Our form doesn't have validation, so let's add it in this lesson.
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.
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.
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.