Laravel Livewire を使って非同期な編集フォームを簡単に作る方法

Livewire では、Eloquent モデルを直接バインドさせることができ、非同期でデータを反映させたり保存するときに大変便利です。

例として、実際に Post モデルのプロパティを編集するためのフォームを作成しながら実装手順といくつかのポイントをご紹介します。

前提

Laravel Livewire 2.x を利用しています。

コンポーネントを新規作成する

まず artisan コマンドを実行して、コンポーネントのひな形を作成します。

コマンド
$ php artisan make:livewire post.show

 COMPONENT CREATED  🤙

CLASS: app/Http/Livewire/Post/Summary.php
VIEW:  resources/views/livewire/post/summary.blade.php

このように表示されたら成功です。

ポイント

「php artisan make:livewire コンポーネント名」だけでも作成できますが、「post.show」のように「サブディレクトリ名.コンポーネント名」を指定すると自動で各サブディレクトリも作成してくれます。

ファイルを綺麗に配置することができてオススメです。

blade ファイルに Livewire コンポーネントを出力する

ルーティングや Controller は通常通りに実装します。

ここでは下記のように実装しました。

routes/web.php
Route::get('/post/{uname}/edit', [PostController::class, 'edit']);
app/Http/Controllers/PostController.php
use App\Models\Post;

public function edit(String $uname)
{
    $post = Post::where('uname', $uname)->first();

    // 略

    return view('post.edit', compact('post'));
}

blade ファイルの中で、 Livewire コンポーネントを表示したい場所に<livewire: />タグを書きます。

resources/views/post/edit.blade.php
<livewire:post.show :post="$post" />

これで show コンポーネントが呼び出されるようになりました。

公式ドキュメント

くわしい書き方のルールはこちらをご覧ください。

https://laravel-livewire.com/docs/2.x/rendering-components

ポイント

非同期に値を更新する機能をつけたいとき、コンポーネントに渡す値は上記のように Eloquent モデル丸ごとがオススメです。後述する手順で Eloquent モデルと直接バインドできるようになります。

Eloquent モデルにバインドする

artisan コマンドで生成された app/Http/Livewire/Post/Show.php を編集して、 blade ファイル経由で受け渡された Eloquent モデルとバインドさせます。

app/Http/Livewire/Post/Show.php
use App\Models\Post;
class Show extends Component
{
    public Post $post;
    protected $rules = [
        'post.title' => 'required|string|max:100',
        'post.summary' => 'string|max:500'
    ];
}

Post モデルの $post を public プロパティとして定義し、 Post モデルのうちバインドしたいプロパティ( title と summary )のバリデーションを $rules プロパティで定義しました。これでバインド完了です。

view ファイルで各プロパティを出力してみます。

resources/views/livewire/post/show.blade.php
<div>
    <input type="text" wire:model="post.title">
    <textarea wire:model="post.summary"></textarea>
</div>

各プロパティの値が表示されていれば成功です!

ポイント

必ず $rules プロパティを設定しなければいけないことに注意してください。

$rules プロパティに代入されたキーのみが正常にバインドされます。

非同期で更新する機能を実装する

Show クラスで更新用の public メソッドを用意します。

app/Http/Livewire/Post/Show.php
public function save()
{
    $this->validate();
    $this->post->save();
}

validate() メソッドでは $rules プロパティに設定されたルールでの検証が行われ、不適合の場合は処理が中断されます。

view ファイルには、フォームを送信( submit )すると save() メソッドを呼び出せるように記述します。

resources/views/livewire/post/show.blade.php
<form wire:submit.prevent="save">
    <input type="text" wire:model="post.title">
    <textarea wire:model="post.summary"></textarea>
    <button type="submit">Save</button>
</form>

ついでにエラー表示もできるようにしておきましょう。

resources/views/livewire/post/show.blade.php
<form wire:submit.prevent="save">
    <input type="text" wire:model="post.title">
    @error('post.title')<p class="text-red-500 text-xs">{{ $message }}</p>@enderror
    <textarea wire:model="post.summary"></textarea>
    @error('post.summary')<p class="text-red-500 text-xs">{{ $message }}</p>@enderror
    <button type="submit">Save</button>
</form>
ポイント

@error(‘post.title’) @enderror 内の $message には post.title に対するエラーが、 @error(‘post.summary’) @enderror 内の $message には post.summary に対するエラーが自動で代入されています。

これで、 Save ボタンを押すと非同期で Post モデルが更新される機能ができました!

フラッシュメッセージを表示する

最後に、データを保存したことをユーザにお知らせするフラッシュメッセージ表示処理を追加します。

app/Http/Livewire/Post/Show.php
public function save()
{
    $this->validate();
    $this->post->save();
    session()->flash('message', '保存しました');
}
resources/views/livewire/post/show.blade.php
<div>
    @if (session()->has('message'))
        <div class="alert alert-success">
            {{ session('message') }}
        </div>
    @endif
</div>

Show クラスで message セッションに値を代入し、それを view ファイルで表示しています。

CSSで見た目を整えたら完成です!