Search code examples
laravellaravel-livewirealpine.js

Livewire component event is not caught


I have a catagory containing a collection of sheetitems and i'm trying to set an edit mode for a newly created sheetItem. I toggle this mode with alpine but i want to set the edit mode via a livewire component property also.

This is my delete component:

<div x-data="{showDeleteButton : false }" x-on:toggle-edit-mode-category-{{ 
$sheetItem->category->id }}.window="showDeleteButton = $event.detail.value">
    <div x-show="showDeleteButton | $wire.showDeleteButton" class="mt-1">
        <div wire:click="deleteSheetItem({{$sheetItem->id}})">
            @include('components.balance.buttons.delete-image')
        </div>
    </div>
</div>

As you can see it is also visible on the following property:

$wire.showDeleteButton

So when i save an Item the following is triggered:

public function saveSheetItem()
{
    $sheetItem = new SheetItem;
    $sheetItem->name = $this->name;
    $sheetItem->amount = Item::convertEurosToEuroCents($this->amount);
    $sheetItem->category_id = $this->category->id;
    $sheetItem->balance_id = $this->balance->id;
    $sheetItem->save();

    $this->resetForm();
    $this->dispatch("sheet-item-saved", id: $sheetItem->id);
}

This triggers the update of my category ans thus my sheetitems in all categories ( planning on making that more specific also ). This triggers "sheet-item-saved". This triggers:

#[On('sheet-item-saved')]
#[On('sheet-item-deleted')]
#[On('updated-show-current-balance')]
public function updateCategory($id = null)
{
    $sheetItemService = new SheetItemService();
    $this->category = $sheetItemService->getCategoryWithSheetItems($this->category);
    $this->getCurrentBalance();

    $this->dispatch("sheet-item-created.{$id}");
}

The new Sheetitem is now created (it shows in the frondend) and another event is triggered to show the delete button for this sheetItem. This should be triggering:

 #[On("sheet-item-created.{sheetItem.id}")]
function showDeleteButton()
{
    Log::error($this->id());
    $this->showDeleteButton = true;
}

But this is not triggered i'm doing it according to the documentation of livewire 3. Livewire Events

Can anyone see why it is not triggering? I tried hardcoding it like so with an id i know exists. That does fire. Could it be that the component does not exist at the time the event is fired?:

 $this->dispatch("sheet-item-created.160");
 #[On("sheet-item-created.160")]

I have also tried logging the different events but that shows a correct order. I did some more logging and there simply isn't a listener present when the event is fired. Al sheetItem Components respond except for the newly created one.


Solution

  • The result: enter image description here

    After some digging i fixed the issue. I did the following.

    This is the view where the event is triggered and the sheetItem is generated. Notice ":show-delete-button="$sheetItem->showDeleteButton", This is a "modelable" property now.

    <div x-data="{ ToggleEditMode : false }" id="{{ 'category-'.$category->id }}" class="card sheet-items-container">
    <div class="flex justify-between card-sub-title">
        <span class="font-bold w-full flex justify-between">
            <div class="flex">
                <div>
                    {{ $category->name }}
                </div>
                <div class="ml-3" x-on:click="$dispatch('toggle-edit-mode-category-{{ $category->id}}', {value: ToggleEditMode = !ToggleEditMode})">
                    <div x-show="!ToggleEditMode">
                        <x-balance.buttons.edit-button x-show="ToggleEditMode" wire:click="showDeleteButtons"/>
                    </div>
                    <div x-show="ToggleEditMode" wire:click="updateCategory">
                        <x-balance.buttons.save-button/>
                    </div>
                </div>
            </div>
            <div x-show="ToggleEditMode">
                @include('components.balance.buttons.delete-button-category')
            </div>
        </span>
    </div>
    <div class="sheet-items-list">
        @foreach($category->sheetItems as $sheetItem)
            <livewire:balance.sheet-items.sheet-item
                :sheet-item="$sheetItem"
                :show-delete-button="$sheetItem->showDeleteButton"
                :key="'sheet-item-'.$sheetItem->id"/>
        @endforeach
    </div>
    </div>
    

    This is where the my delete component is included in " livewire:balance.sheet-items.sheet-item/":

    <div x-bind:class="$wire.showCurrentBalance ? 'sheet-item-input-amount-income-day' : 'sheet-item-input-amount-no-income-day'"
         class="flex place-items-center">
        <div class="pt-1">&euro;</div>
        <x-input
            wire:model.live="amount"
            class="text-right"
            type="text"
        />
        <template x-if="!$wire.showCurrentBalance">
            <div class="ml-1">
                @include('components.balance.buttons.delete-button-sheet-item')
            </div>
        </template>
    </div>
    <template x-if="$wire.showCurrentBalance">
        <div class="flex flex-row-reverse">
            @include('components.balance.buttons.delete-button-sheet-item')
            <div>
                <div class="flex place-items-center justify-end">
                    <div class="pt-1 mr-1">&euro;{{ $total }}</div>
                </div>
            </div>
        </div>
    </template>
    

    This is my delete component, the key difference is that this changed from "showDeleteButton | $wire.showDeleteButton" to "$wire.showDeleteButton" and i changed it to:

    x-on:toggle-edit-mode-category-{{ $sheetItem->category->id }}.window="$wire.showDeleteButton = $event.detail.value
    

    So if i toggle it with alpine or set the property in my component the delete button will show:

    <div x-data="{showDeleteButton : false }" x-on:toggle-edit-mode-category-{{ $sheetItem->category->id }}.window="$wire.showDeleteButton = $event.detail.value">
    <div x-show="$wire.showDeleteButton" class="mt-1">
        <div wire:click="deleteSheetItem({{$sheetItem->id}})">
            @include('components.balance.buttons.delete-image')
        </div>
    </div>
    

    This happens in the following order. A new sheetItem is saved:

    public function saveSheetItem()
    {
        $sheetItem = new SheetItem;
        $sheetItem->name = $this->name;
        $sheetItem->amount = Item::convertEurosToEuroCents($this->amount);
        $sheetItem->category_id = $this->category->id;
        $sheetItem->balance_id = $this->balance->id;
        $sheetItem->save();
    
        $this->resetForm();
        $this->dispatch("sheet-item-saved." . $sheetItem->category->id, id: $sheetItem->id);
    }
    

    The event is caught and for some reason the item is present in the sheetitems collection, i set the "showDeleteButton" property wich is "modelable", and the delete button shows:

    #[On('sheet-item-saved.{category.id}')]
    function addSheetItemToCategory($id)
    {
        $this->category->sheetItems->map(function ($sheetItem) use ($id) {
            if ($sheetItem->id === $id) {
                $sheetItem->showDeleteButton = true;
                $sheetItem->total = Item::convertEuroCentsToEuros($sheetItem->count * $sheetItem->amount);
                $sheetItem->amount = Item::convertEuroCentsToEuros($sheetItem->amount);
            }
            return $sheetItem;
        });
    }
    

    It's a bit of a long story but maybe someone is helped with it.