Laravelでの動的なページ作成方法の1つであるLivewireの利用方法をまとめました。
この記事を読むことで入力フォームにある項目の数を動的に変更できるようになります。応用できれば、リアルタイムで入力値のバリデーションや入力のサジェスチョンなどもできるようになると思います。
また、動的(ダイナミック)でモダンなページを作成する方法は、ReactやVue.jsがメジャーですが、新たに純粋にLaravelからWebアプリ開発を始めた人にとっては、javascriptとそのフレームワークを新たに学ぶ必要があります。しかし、本記事ではLaravelのエコシステムに含まれるLivewire3.0を使用して動的ページを実現するため、PHPと本記事の知識があれば十分開発に応用できます。
本記事で紹介する動的ページ

このgifのようにボタン操作によって、テキスト入力欄を動的に増減させるフォームを作成する方法を紹介します。
本記事の例ではアドレス帳に相手の情報(名前、誕生日、複数の電話番号、複数のメールアドレス)を登録する画面を作成します。
LIVEWIRE使い方
Livewireのインストール
Laravelアプリのプロジェクトディレクトリトップで下記のコマンドを実行します。
sail composer require livewire/livewireこのコマンドを実行すると、インストールが行われ、sail環境ではcomposer.json, composer.lockも更新されます。
Livewireコンポーネントの作成
Livewireのコンポーネントは下記コマンドで作成します。
sail artisan make:livewire AddressBook/Createコマンドを実行すると、app/Livewire/AddressBook/Create.phpとresources/views/livewire/AddressBook/create.blade.phpが作成されます。
Livewireコンポーネントクラスの編集
Livewireのコンポーネントクラスでは、ビューと連動する変数やクリックなどのイベントに応じて呼び出すメソッドを定義します。
本記事の例では、電話番号とメールアドレスを複数登録できるように配列を持ちます。そして、ビューで入力フォームを増減させるためのメソッドを用意しました。
<?php
namespace App\Livewire\AddressBook;
use Livewire\Component;
class Create extends Component
{
//ビューと連動する変数
public $phones = [];
public $mails = [];
public function render()
{
return view('livewire.AddressBook.create');
}
//以下ビューから呼び出す関数
public function addPhone(){
$this->phones[] = '';
}
public function removePhone($index){
unset($this->phones[$index]);
$this->phones = array_values($this->phones);
}
public function addMail(){
$this->mails[] = '';
}
public function removeMail($index){
unset($this->mails[$index]);
$this->mails = array_values($this->mails);
}
public function save(){
//本当ならモデルにデータを追加するところ
dd($this);
}
}
Livewireビューの編集
Livewireのビューでは、「wire:model」を使用して連動するコンポーネントクラスの変数や、「wire:click」を使用してクリック時に呼び出すコンポーネントクラスの関数を記載します。
resources/views/livewire/AddressBook/create.blade.phpのなかでは、コンポーネントに用意した電話番号やメールアドレスと入力欄の値を連動させたり、ボタンによって入力欄の増減やフォームの送信の関数と結び付けたりします。
具体的には下記のようなビューになります。
<div>
<form wire:submit="save">
<div>
<label>名前</label>
<input type="text" name="name">
</div>
<div>
<label>誕生日</label>
<input type="date" name="birth_day">
</div>
<div>
@foreach ($phones as $phone)
<div>
<label>電話番号{{ $loop->index +1 }}</label>
<input type="tel" wire:model='phones.{{$loop->index}}' value='{{ $phones[$loop->index]}}'>
<button type='button' wire:click='removePhone({{ $loop->index }})'>-</button>
</div>
@endforeach
<button type='button' wire:click='addPhone'>電話番号追加</button>
</div>
<div>
@foreach ($mails as $mail)
<div>
<label>メールアドレス{{ $loop->index +1}}</label>
<input type="email" wire:model='mails.{{$loop->index}}'>
<button type='button' wire:click='removeMail({{ $loop->index}})'>-</button>
</div>
@endforeach
<button type='button' wire:click='addMail'>メールアドレス追加</button>
</div>
<button type="submit">連絡先の保存</button>
</form>
</div>
テンプレートレイアウトを作成する
livewireコンポーネントはデフォルトでテンプレートのレイアウトとなる下記ファイルを探して、構成されます。
resources/views/components/layouts/app.blade.php
このファイルを作成するために下記コマンドを実行します。実行後に作成されるファイルを編集することで各ページ共通の見た目を作成できます。
sail artisan livewire:layoutLivewireコンポーネントへルートティング
最後にroutes/web.phpに下記の行を追加します。
use App\Livewire\AddressBook\Create;
Route::get('/address-book/create', Create::class);以上の実装を行った後、定義したURLにアクセスすると次のような入力画面が確認できます!

感想
長期的に見れば、javascriptを使えるようになり、フロントエンドはよりメジャーなvue.jsやReactを使るようになるのが良い気もしますが、PHPだけで書けるLivewireは学習時間をあまりとれない場合は助かりますね。
また、コントローラを経由せずに実装する場合は、MVCではなくMVVMに近いのかなーと思います。もう少し勉強して、どういうデザインパターンがいいのか再考したいと思いました。


コメント