はじめに
この記事ではPrecognition
というツールを使ってInertia + Vue
のバリデーションを実装する方法について書いています。
Precognition
はLaravelのフォームリクエストで定義したバリデーションを使用して、Vue等のフロントエンドでも使用するためのライブラリです。つまりバリデーションをLaravel側に統一することができます。
前提
- Laravel + Vue + Inertiaで環境構築ができている
- サンプルコードには
<script setup>
構文を使う
Precognitionを導入・設定
以下の順に作業を行っていきます。
- フォームリクエストを作成
- コントローラーを作成
- Precognitionをインストール
- ルーティングを設定
- Vueファイルを作成
Precognition
の導入方法だけを確認したい方は3.から見ていただければと思います。
それでは説明してきます。
フォームリクエストを作成
まずはフォームリクエストのファイルを作成します。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|max:255',
'email' => 'required',
];
}
}
このようにフォームリクエストは普通にバリデーションを定義するだけで、Vue側にエラーメッセージを表示することができます。
コントローラーを作成
次にコントローラーを作成します。
<?php
namespace App\Http\Controllers;
use App\Http\Requests\UserRequest;
use Inertia\Inertia;
class UserController extends Controller
{
public function index()
{
return Inertia::render('users/index');
}
public function store(UserRequest $request)
{
return Inertia::render('users/index');
}
}
今回はバリデーションが実装できているかどうかのみを確認するため、$request
は使いません。
Precognitionをインストール
ライブラリのインストールを行います。
$ npm install laravel-precognition-vue-inertia
上記はInertia + Vue
用のライブラリをインストールするためのコマンドになります。
ルーティングを設定
ルートに対してPrecognition
を適用する必要があります。
下記のようにルートを定義します。
<?php
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
// 略
Route::get('/users', [UserController::class, 'index']);
Route::post('/users', [UserController::class, 'store'])->middleware([HandlePrecognitiveRequests::class]);
ミドルウェアとして設定しているHandlePrecognitiveRequests::class
でPrecognition
を適用することができます。
Vueファイルを作成
最後にVueファイルを作成します。
<script setup>
import { useForm } from "laravel-precognition-vue-inertia"
const form = useForm("post", "/users", {
name: "",
email: ""
})
const submit = () =>
form.submit({
// trueにしておくとリダイレクトされた際にフォームの場所までスクロールしてくれる
preserveScroll: true,
// リクエスト成功時にフォームに入力された内容をリセットする
onSuccess: () => form.reset()
})
</script>
<template>
<form @submit.prevent="submit">
<div>
<label for="name">名前</label>
<input id="name" v-model="form.name" />
<div v-if="form.invalid('name')" class="error-message">
{{ form.errors.name }}
</div>
</div>
<div>
<label for="email">メールアドレス</label>
<input
id="email"
type="email"
v-model="form.email"
@change="form.validate('email')"
/>
<div v-if="form.invalid('email')" class="error-message">
{{ form.errors.email }}
</div>
</div>
<button :disabled="form.processing">Create User</button>
</form>
</template>
<style scoped>
form {
padding: 10px;
}
label {
display: block;
}
button {
margin-top: 10px;
}
.error-message {
color: red;
}
</style>
フォームに何も入力せずに作成ボタンを押すと下記のようにエラーメッセージが表示されます。
また、名前フォームに256以上入力して作成ボタンを押すと、文字数超過のメッセージが表示されます。
これでフォームリクエストのバリデーションが適用されていることがわかりました。
補足
リクエストを送信した際に特定のタイミングで何かしらの処理走らせることができます。
<script setup>
// 略
const submit = () =>
form.submit({
onBefore: (visit) => console.log("before", visit), // リクエスト前
onStart: (visit) => console.log("start", visit), // リクエスト開始時
onError: (errors) => console.log("error", errors), // バリデーションエラー発生時
onFinish: (visit) => console.log("finish", visit), // リクエスト処理の終了時
onSuccess: (page) => console.log("success", page), // リクエスト成功時
})
</script>
// 略
onFinish
はリクエストが成功しても失敗しても実行されます。また、各アロー関数の引数で定義しているvisit
、errors
などはフォームの入力値やエラーメッセージ等が格納されています。気になる方は実際に確認してみてください。
参考