概要
livewireとAlpine.jsは相性が良い!!
livewireにAlpine.jsをトッピング!!
という文言をチラホラみかけます。
自分も普段livewireにalpine.jsをチラホラ使いますが(x-show
ぐらい)
キッチリ使った事が無かったのでフロントをAlpine.jsバックをlivewireで分けてみようと思います。
投稿機能のようなものを作ってみる
- タイトルと内容を入力して送信する所まで作る
- フロントにlivewireディレクティブを書かない
コード
x-adminlteコンポーネントを使用していますがただのinputタグです
php側
<?php
namespace App\Http\Livewire\Board;
use Livewire\Component;
class Create extends Component
{
public array $board;
public function mount(): void
{
$this->board = ['title' => null, 'content' => null];
}
public function render()
{
return view('livewire.board.create')
->extends('adminlte::page')
->section('content');
}
public function create(): void
{
dd($this->validate()['board']);
}
protected function rules(): array
{
return [
'board.title' => 'required',
'board.content' => 'nullable',
];
}
protected function validationAttributes(): array
{
return [
'board.title' => 'タイトル',
'board.content' => '内容',
];
}
}
<div class="pt-3">
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div class="col-6 card card-body" x-data="boardApp">
<form @submit.prevent="handleSubmit">
<x-adminlte-input name="board.title" label="タイトル"
x-model="board.title"/>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1" x-model="isContentEdit">
<label class="form-check-label" for="exampleCheck1">内容を入力する</label>
</div>
<x-adminlte-textarea name="board.content" label="内容"
x-bind:disabled="!isContentEdit"
x-model="board.content"/>
<x-adminlte-button label="登録" theme="primary" type="submit"/>
</form>
</div>
<script>
const boardApp = () => ({
//livewireコンポーネントのboardと同期
board: @entangle('board').defer,
isContentEdit: false,
init() {
//isContentEditの変更を検知
this.$watch('isContentEdit', (isContentEditValue) => {
//false時に値をnullに
if (!isContentEditValue) {
this.board.content = null;
}
});
},
handleSubmit() {
//livewireコンポーネントのcreateメソッド発火
this.$wire.create();
}
})
document.addEventListener('alpine:init', () => {
Alpine.data('boardApp', boardApp);
});
</script>
</div>
出来た画面
livewireだけで書いてみる
「内容を入力する」が切り替わるたびにリクエストが走りますが、
基本的に同じような感じに動きます。
<?php
namespace App\Http\Livewire\Board;
use Livewire\Component;
class Create extends Component
{
public array $board;
+ public bool $isContentEdit;
public function mount(): void
{
$this->board = ['title' => null, 'content' => null];
+ $this->isContentEdit = false;
}
public function render()
{
return view('livewire.board.create')
->extends('adminlte::page')
->section('content');
}
public function create(): void
{
dd($this->validate()['board']);
}
+ public function updatedIsContentEdit()
+ {
+ if (!$this->isContentEdit) {
+ $this->board['content'] = null;
+ }
+ }
protected function rules(): array
{
return [
'board.title' => 'required',
'board.content' => 'nullable',
];
}
protected function validationAttributes(): array
{
return [
'board.title' => 'タイトル',
'board.content' => '内容',
];
}
}
<div class="pt-3">
<div class="col-6 card card-body">
<form wire:submit.prevent="create">
<x-adminlte-input name="board.title" label="タイトル" wire:model.defer="board.title"/>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1" wire:model.lazy="isContentEdit">
<label class="form-check-label" for="exampleCheck1">内容を入力する</label>
</div>
<fieldset @if(!$isContentEdit) disabled @endif>
<x-adminlte-textarea name="board.content" label="内容"
wire:model.defer="board.content"/>
</fieldset>
<x-adminlte-button label="登録" theme="primary" type="submit"/>
</form>
</div>
</div>
おわりに
上記は唯のサンプルですが、
Bladeに書く処理を少なくしたり(分岐とか)
可能な限りリクエスト数を少なくする為にはAlpine.jsも使い慣れておく必要がありそうなので、ちらほら勉強しようと思います。