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)を使う手順。
- プロジェクト名(rating)を決めて以下のコマンドを実行します。
curl -s https://laravel.build/rating | bash
インストール時にプロジェクト名のディレクトリが作成されます。
- インストールの最後に 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
- sail のエイリアスを定義します。
echo "alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'" >> ~/.bashrc
source ~/.bashrc
Laravel のインストールはここまで。
- 「sail up」でコンテナを起動します。
cd rating && sail up -d
- ララベルのトップディレクトリで、Livewireパッケージ をインストールします。
sail composer require livewire/livewire
- 次のコマンドを実行して、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
{
}
- 生成された 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’,…)」です。
- 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>
- routes/web.php に Livewireコンポーネント のルートを追加します
Route::get('/', fn() => view('index'));
- ブラウザで確認します。
tail で onRate(ユーザーが評価を選択した後)のタイミングで通信していることを確認しましょう。
tail -f storage/logs/laravel.log
ちょっと、どうにかならないのかなと思うのが2点
①Ratingクラスに updatedメソッドを作り、イベントを発行しなければならない点。
②rating.blade.php でイベントを受け取り、再描画する為に ratingメソッド が2回呼ばれている点。
- ①に関しては、イベントを発行する場所をデハイドレートにして解決できました。
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;
}
}
- ②に関しては、評価コンポーネントの最初の描画は 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
- 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>
以上