Livewire で Fomantic-UI の評価(Rating)を使うには?wire:ignore使わない編

ショコラ
ショコラ

Livewire で Fomantic-UI の評価(Rating)を使うには?wire:ignore使わない編

Fomantic-UI の評価(Rating)のように、wire:model が使えないコントーラー(text、radio、checkbox、select、textarea以外)を使うには、どうしたらいいのでしょうか?

今回、「評価(Rating)」を使って確認してみようと思います。

ポイントは
①wire:ignore を使わないところ
onRate(ユーザーが評価を選択した後)のタイミングで 「@this.set(‘rating’,value,[defer]) 」でプロパティを設定するところ
③アクションメソッドで変更した内容を反映させる為に、アクションメソッドからイベントを発行して 評価コンポーネントを再描画するところです。

もっさん先輩
もっさん先輩

手順

Laravel と Livewire をインストールして、Fomantic-UI の評価(Rating)を使う手順。

  1. プロジェクト名(rating)を決めて以下のコマンドを実行します。
curl -s https://laravel.build/rating | bash

インストール時にプロジェクト名のディレクトリが作成されます。

  1. インストールの最後に sudo でパスワードの入力を求められます。

↓下のメッセージが表示されてインストールは終わります。

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

Get started with: cd rating && ./vendor/bin/sail up
  1. sail のエイリアスを定義します。
echo "alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'" >> ~/.bashrc
source ~/.bashrc

Laravel のインストールはここまで。

  1. 「sail up」でコンテナを起動します。
cd rating && sail up -d
  1. ララベルのトップディレクトリで、Livewireパッケージ をインストールします。
sail composer require livewire/livewire
  1. 次のコマンドを実行して、ratingコンポーネント を生成します。
sail artisan make:livewire rating
$ sail artisan make:livewire rating
 COMPONENT CREATED  ?

CLASS: app/Http/Livewire/Rating.php
VIEW:  resources/views/livewire/rating.blade.php

次の 2つ のファイルが生成されます。

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Rating extends Component
{
    public function render()
    {
        return view('livewire.rating');
    }
}
<div>
    {{-- The Master doesn't talk, he acts. --}}
</div>

※因みに、renderメソッド を定義しなくても livewire.rating は呼び出されます。

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Rating extends Component
{
}
  1. 生成された ratingコンポーネント のクラスとビューを次のように置き換えます。

app/Http/Livewire/Rating.php

<?php
namespace App\Http\Livewire;
class Rating extends \Livewire\Component
{
  public $rating = 5;
  public $max_rating = 10;
  public $icon = 'star';

  public function dehydrate() {
    \Log::debug($this->rating);
  }
  public function dec() {
    --$this->rating;
    $this->emit('refresh');
  }
  public function inc() {
    ++$this->rating;
    $this->emit('refresh');
  }
  public function updated($field, $newValue) {
    $this->emit('refresh');
  }
}

↑上のポイントは、プロパティ更新時の updatedメソッド で、refreshイベント を発行して評価コンポーネントを再描画するようにしているところです。

resources/views/livewire/rating.blade.php

<div>
  <div class="ui rating {{ $this->id }}" data-icon="{{ $icon }}" data-rating="{{ $rating }}" data-max-rating="{{ $max_rating }}"></div>
  <input type="button" wire:click="dec" value="-">
  <input type="button" wire:click="inc" value="+">
<script>
// ratingを表示する。評価変更時にプロパティに設定する。
$('.{{ $this->id }}').rating({onRate:value => @this.set('rating',value,false)})

document.addEventListener('livewire:load',() => {
  // リフレッシュイベントでコンポーネントを再描画する。
  Livewire.on('refresh',() => $('.{{ $this->id }}').rating({
    onRate:value => @this.set('rating',value,false)
  }))
})
</script>
</div>

ポイントは1行目の「wire:ignore」を消したところと、「@this.set()」「Livewire.on(‘set-rating’,…)」です。

  1. resources/views/index.blade.php ファイル を作成します。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.0/dist/semantic.min.css">
    <script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.0/dist/semantic.min.js"></script>
    <livewire:styles />
  </head>
  <body>
    <div class="ui basic segment">
      <livewire:rating />
    </div>
    <livewire:scripts />
  </body>
</html>
  1. routes/web.php に Livewireコンポーネント のルートを追加します
Route::get('/', fn() => view('index'));
  1. ブラウザで確認します。

tail で onRate(ユーザーが評価を選択した後)のタイミングで通信していることを確認しましょう。

tail -f storage/logs/laravel.log

ちょっと、どうにかならないのかなと思うのが2点
①Ratingクラスに updatedメソッドを作り、イベントを発行しなければならない点。
②rating.blade.php でイベントを受け取り、再描画する為に ratingメソッド が2回呼ばれている点。

  1. ①に関しては、イベントを発行する場所をデハイドレートにして解決できました。

app/Http/Livewire/Rating.php

<?php
namespace App\Http\Livewire;
class Rating extends \Livewire\Component
{
  public $rating = 5;
  public $max_rating = 10;
  public $icon = 'star';

  public function dehydrate() {
    \Log::debug($this->rating);
    $this->emit('create');
  }
  public function dec() {
    --$this->rating;
  }
  public function inc() {
    ++$this->rating;
  }
}
  1. ②に関しては、評価コンポーネントの最初の描画は JavaScriptでイベントを発行して表示するようにしました。

resources/views/livewire/rating.blade.php

<div>
  <div class="ui rating {{ $this->id }}" data-icon="{{ $icon }}" data-rating="{{ $rating }}" data-max-rating="{{ $max_rating }}"></div>
  <input type="button" wire:click="dec" value="-">
  <input type="button" wire:click="inc" value="+">
</div>

@push ('create')
Livewire.on('create',() => $('.{{ $this->id }}').rating({
  onRate: value => @this.set('rating',value,false)
}))
@endpush
  1. resources/views/index.blade.php ファイル を作成します。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.0/dist/semantic.min.css">
    <script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.0/dist/semantic.min.js"></script>
    <livewire:styles />
  </head>
  <body>
    <div class="ui basic segment">
      <livewire:rating />
    </div>
    <livewire:scripts />
<script>
document.addEventListener('livewire:load',() => {
  @stack ('create')
  Livewire.emit('create')
})
</script>
  </body>
</html>

以上

Scroll to Top