13

Livewire how to $emit event on <select> change (wire:model)

I need to fire event (fetch some data from DB in another component) on simple <select> change.

<select id="hall" wire:model="hall_id">...</select>

How to watch changes for this model? On VueJS we just set $watch or $computed properties, I believe in livewire should be something similar. It's strange why there is no wire:change directive.

This is how I'm trying to emit event now:

<?php

namespace App\Http\Livewire;

use App\Models\Event;
use App\Models\Hall;
use Livewire\Component;

class ShowReservationForm extends Component
{
    public $hall_id = '';

    protected $queryString = [
        'hall_id' => ['except' => ''],
    ];

    public function mounted()
    {
        //
    }

    public function updatedHallId($name, $value)
    {
        $this->emit('hallChanged', $value);
    }

    public function render()
    {
        return view('livewire.show-reservation-form', [
            'halls' => Hall::all(),
        ]);
    }

    public function getHallEventsProperty()
    {
        return Event::where('hall_id', $this->hall_id)->get();
    }
}

and catch it:

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class ShowReservations extends Component
{
    protected $listeners = ['hallChanged'];

    public $showTable = false;

    public function render()
    {
        return view('livewire.show-reservations');
    }

    public function hallChanged()
    {
        $this->showTable = true;
    }
}

Must be missing something obvious.

RomkaLTU
  • 3,683
  • 8
  • 40
  • 63
  • Doesn't work at all, trying put `$this->emit('hallChanged')` everywhere ;D – RomkaLTU Oct 05 '20 at 06:54
  • Do you enter the `updatedHallId()` method when the field is changed? Add a `dd('Test');` or similar in that method. – Qirel Oct 05 '20 at 07:56
  • There's not really a need for `wire:change`, because you just listen for the updated event for that property from the component. – Qirel Oct 05 '20 at 07:57
  • dd() in updatedHallId indeed working but this part seams not: $this->emit('hallChanged', $value); Or maybe something wrong with $listeners – RomkaLTU Oct 05 '20 at 09:32
  • And both components are on the same page? They cannot emit events to other users or other pages. You need broadcasting for that. – Qirel Oct 05 '20 at 09:37
  • Yes, they are on dashboard.blade.php @livewire('show-reservation-form') and @livewire('show-reservations') – RomkaLTU Oct 05 '20 at 09:39
  • And have you verified that you enter the `hallChanged` method in your `ShowReservations` component? – Qirel Oct 05 '20 at 09:41
  • @RomkaLTU please check my answer i tested in my side it is working – Kamlesh Paul Oct 05 '20 at 09:42
  • Yes, protected $listeners = ['hallChanged']; Because method are same name, also tried protected $listeners = ['hallChanged' => 'hallChanged']; no dice. @KamleshPaul I don't have problem with change event, only with emitter. – RomkaLTU Oct 05 '20 at 09:44
  • I ran into a similar problem maybe my question & answer can help https://stackoverflow.com/questions/64379725/how-can-i-create-dynamic-public-properties-and-data-via-a-parent-component-to-a/ – Daniel Tate Oct 15 '20 at 22:52

3 Answers3

18

use wire:change

<select id="hall" wire:model="hall_id" wire:change="change">...</select>

then in component

In ShowReservationForm.php

public function change()
{
     $this->emit('hallChanged'); 
}

then you can listen it on ShowReservations component ref link https://laravel-livewire.com/docs/2.x/events

in ShowReservations.php

 protected $listeners = ['hallChanged' => 'change'];

public function change()
{
   $this->showTable = true;
}
Kamlesh Paul
  • 11,778
  • 2
  • 20
  • 33
  • 1
    I actualy don’t want to use JS, It would be very awkward. And I use version 2 of livewire. – RomkaLTU Oct 05 '20 at 07:09
  • by the way what you are doing with `showTable` ? you can directly do `@if(!empty($hall_id)) table @endif` – Kamlesh Paul Oct 05 '20 at 07:13
  • That table is in another component ant initial state is false and yes I'm doing simple @if statement. So what I'm trying to do is to change that $showTable property to true. – RomkaLTU Oct 05 '20 at 07:14
4

It's turns out that when receiving event, property value must not be bool?

This will not work:

public $showTable = false;
...
public function hallChanged()
    {
        $this->showTable = true;
    }

This will work

public $showTable = 0;
...
public function hallChanged()
    {
        $this->showTable = 1;
    }
RomkaLTU
  • 3,683
  • 8
  • 40
  • 63
1

If the code not works, take a look about any [for example jQuery] handle for your select, maybe it handled by select2 script or so, if so - LiveWire will not work from scratch. The rigth minimal code is:

/resources/views/livewire/your-livewire-component.blade.php

<select wire:model="country">
    @foreach($items as $code => $country)
        <option value="{{ $code }}">{{ $country }}</option>
    @endforeach
</select>

/app/Http/Livewire/YourLivewireComponent.php

<?php
namespace App\Http\Livewire;
use Illuminate\Support\Facades\Log;
use Livewire\Component;
class YourLivewireComponent extends Component
{
    public $items;
    public $country; //necessary!
    public function mount($items)
    {
        $this->items = $items;
    }

    public function render()
    {
        return view('livewire.your-livewire-component', [
            'items' => ['ES' => 'Spain', 'FI' => 'Finland']
        ]);
    }

    public function updatedCountry($value)
    {
        Log::info('value='.print_r($value, 1));
    }
}

/resources/views/somelaraveltemplate.blade.php

<p>some HTML code</p>
@livewire('your-liveweire-component')
Igor
  • 755
  • 1
  • 10
  • 22