LoginSignup
5
2

More than 1 year has passed since last update.

Alpine.js「───やっと気づいた。livewireは、私の鞘だったのですね」

Last updated at Posted at 2022-12-13

概要

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>

出来た画面

画面収録 2022-12-06 19.gif

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も使い慣れておく必要がありそうなので、ちらほら勉強しようと思います。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2