I am currently debugging an event that I have dispatched to be listened to where once the event is dispatched other components can listen and emit the event. Here is my code
CreatePost.php
<?php
namespace App\Livewire;
use Livewire\Attributes\Rule;
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
#[Rule('required')]
#[Rule('min:5')]
public $title;
#[Rule('required')]
#[Rule('min:10')]
public $content;
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function save()
{
$this->validate();
$post = Post::create([
'title' => $this->title,
'content' => $this->content,
]);
$this->dispatch('post-created', title: $post->title);
return redirect()->to('/posts')
->with('status', 'Post created!');
}
}
and ShowPost Component
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\On;
use App\Models\Post;
class ShowPosts extends Component
{
public $posts;
public function mount()
{
$this->posts = Post::all();
}
#[On('post-created')]
public function refreshPosts($title)
{
$this->posts = Post::all();
session()->flash('message', 'A new post was created:' . $title);
}
public function render()
{
return view('livewire.show-posts');
}
}
This component will listen to the CreatePost component and display the event but it's not shown when I create a new post here
show-posts.blade.php
<div>
<h1>All Posts</h1>
@if (session()->has('message'))
<div class="alert alert-success">
{{ session('message') }}
</div>
@endif
@foreach($posts as $post)
<div>
<h3>{{ $post->title }}</h3>
<p>{{ $post->content }}</p>
<livewire:show-comments :postId="$post->id" :key="$post->id"/>
</div>
@endforeach
</div>
I finally solved it by removing
return redirect()->to('/posts')
->with('status', 'Post created!');
from CreatePost component
As I discovered livewire components must be on the same page for event listeners to work. The above code was redirecting the user to ShowPost page where the event listener could not be displayed since they were different pages.
But I have placed them on the same page like this...
<title>{{ $title ?? 'Page Title' }}</title>
</head>
<body>
@livewire('create-post')
@livewire('show-posts')
@livewireScripts
</body>
</html>
And my CreatePost looks like this
<?php
namespace App\Livewire;
use Livewire\Attributes\Rule;
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
#[Rule('required')]
#[Rule('min:5')]
public $title;
#[Rule('required')]
#[Rule('min:10')]
public $content;
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function save()
{
$this->validate();
$post = Post::create([
'title' => $this->title,
'content' => $this->content,
]);
$this->dispatch('post-created', ['title' => $post->title]);
session()->flash('message', 'Post created!');
}
}
And my ShowPost
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\On;
use App\Models\Post;
class ShowPosts extends Component
{
public $posts;
public function mount()
{
$this->posts = Post::all();
}
#[On('post-created')]
public function refreshPosts($data)
{
$title = $data['title'];
$this->posts = Post::all();
session()->flash('message', 'A new post was created: ' . $title);
}
public function render()
{
return view('livewire.show-posts');
}
}
Lastly show-posts.blade.php
<div>
<h1>All Posts</h1>
@if (session()->has('message'))
<div class="alert alert-success">
{{ session('message') }}
</div>
@endif
@foreach($posts as $post)
<div>
<h3>{{ $post->title }}</h3>
<p>{{ $post->content }}</p>
<livewire:show-comments :postId="$post->id" :key="$post->id"/>
</div>
@endforeach
</div>