Search code examples
phplaravellaravel-livewire

Event listeners not working in laravel-livewire 3


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>

Solution

  • 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>