Feb 19, 2025
0
Level 1
Livewire + AlpineJS - showButton is not defined
Hello, I have built a small LMS where users can create courses and add episodes to them. The episode playback is designed so that when an episode is watched, a button appears indicating that the video has been viewed. Clicking this button automatically loads the next episode and records in the database which episodes the user has already watched.
However, after watching the first episode and clicking the button, I get the following error message in the console:
Alpine Expression Error: showButton is not defined
Expression: "showButton"
<button class="mt-4 p-2 bg-green-500 text-white rounded" x-show="showButton" wire:click="confirmWatched">
Uncaught ReferenceError: showButton is not defined
What could be the issue? I appreciate any responses.
Projekt
- Laravel 11
- Livewire 3.5
- AlpineJs 3.4.2
EpisodePlayer.php
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Episode;
use App\Models\CourseUserProgress;
use Illuminate\Support\Facades\Auth;
class EpisodePlayer extends Component
{
public Episode $episode;
public int $episodeId;
public bool $watched = false;
protected $listeners = [
'videoEnded' => 'setAsWatched',
'episodeChanged' => 'updateEpisode',
];
public function mount(Episode $episode)
{
$this->episode = $episode;
$this->episodeId = $episode->id;
$this->reloadWatchedStatus();
}
public function updateEpisode($episodeId)
{
$newEpisode = Episode::find($episodeId);
if ($newEpisode) {
$this->episode = $newEpisode;
$this->episodeId = $newEpisode->id;
$this->watched = false; // Reset the state for a new episode
$this->reloadWatchedStatus();
$this->dispatch('$refresh'); // UI re-rendering
}
}
public function reloadWatchedStatus()
{
$this->watched = CourseUserProgress::where('user_id', Auth::id())
->where('episode_id', $this->episode->id)
->exists();
}
public function setAsWatched($episodeId)
{
if ((int) $episodeId === $this->episode->id) {
$this->watched = true;
$this->dispatch('$refresh'); // UI re-rendering
}
}
public function confirmWatched()
{
if ($this->watched) {
CourseUserProgress::create([
'user_id' => Auth::id(),
'course_id' => $this->episode->course_id,
'episode_id' => $this->episode->id,
]);
$this->watched = true;
$this->dispatch('episodeWatched', episodeId: $this->episode->id)->to(CourseShow::class);
$this->dispatch('$refresh'); // UI re-rendering
}
}
public function render()
{
return view('livewire.episode-player');
}
}
episode-player.blade.php
<div x-data="{
episodeId: @entangle('episodeId'),
watched: @entangle('watched'),
showButton: false,
init() {
console.log('Alpine.js initialized - episode ID:', this.episodeId);
this.$watch('episodeId', (newEpisodeId) => {
console.log('New episode loaded:', newEpisodeId);
this.showButton = false; // Reset button
this.setupVideoListener();
});
this.setupVideoListener();
},
setupVideoListener() {
setTimeout(() => {
let video = document.getElementById('videoPlayer');
if (video) {
console.log('Video monitoring is enabled for the episode:', this.episodeId);
video.addEventListener('ended', () => {
console.log('Video ende - Send event to Livewire:', this.episodeId);
window.Livewire.dispatch('videoEnded', { episodeId: this.episodeId });
this.showButton = true;
});
} else {
console.warn('Video player not found!');
}
}, 500);
}
}"
x-init="init()"
@video-ended.window="if ($event.detail.episodeId == episodeId) showButton = true"
>
<h3 class="text-lg font-semibold mb-2">{{ $episode->title }}</h3>
@if ($episode->video_url)
<video id="videoPlayer" class="w-full h-auto" controls>
<source src="{{ $episode->video_url }}" type="video/mp4">
Your browser does not support playing the video.
</video>
<button
x-show="showButton"
class="mt-4 p-2 bg-green-500 text-white rounded"
wire:click="confirmWatched">
I watched the video.
</button>
@else
<p class="text-red-500">There is no video uploaded for this episode.</p>
@endif
</div>
Please or to participate in this conversation.