Search code examples
laravellaravel-livewirealpine.js

Having onClick event and wire:click under the same element


I have a href link with an onclick event and a wire:click. The onclick event calls a slideover function inside the javascript. When clicked, the slider should go up from the right side with some data, and the wire:click="getOrder({{$orderId}})" should retrieve the order. Both work, but the slider slides back when it retrieves the order from the server. If I remove the wire:click, the slider stays, but I can't retrieve the order. Here's my slider code:

<div> 
<div id="slideover-container" class="fixed inset-0 w-full h-full invisible z-50">
    <div onclick="toggleSlideover()" id="slideover-bg" class="absolute duration-500 ease-out transition-all inset-0 w-full h-full bg-gray-900 opacity-0"></div>
    <div id="slideover" class="absolute w-3/4 duration-500 ease-out transition-all h-full bg-white right-0 top-0 translate-x-full">
        <div onclick="toggleSlideover()" class="w-10 h-10 flex items-center shadow-sm rounded-full justify-center hover:bg-gray-200 cursor-pointer absolute top-0 right-0 m-2">
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
                <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
            </svg>
        </div>
        <div class="p-4 relative mt-20">
            
            <input type="hidden" id="{{$orderId}}">
            <table x-ref="table" class="w-full text-sm text-left rtl:text-right dark:text-gray-400">
                <thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
                    <tr>
                        <th scope="col" class="px-3 py-3">Amount</th>
                        <th scope="col" class="px-3 py-3">Ref #</th>
                        <th scope="col" class="px-3 py-3">Payment</th>
                        <th scope="col" class="px-3 py-3">Date</th>
                        <th scope="col" class="px-3 py-3">Action</th>
                    </tr>
                </head>
                <tbody>
                    <tr class="odd:bg-white hover:bg-gray-50 odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800 border-b dark:border-gray-700">
                        <td class="px-3 py-2"></td>
                        <td class="px-3 py-2"></td>
                        <td class="px-3 py-2"></td>
                        <td class="px-3 py-2 text-center"></td>
                        <td class="px-3 py-2 text-center">
                            <button type="button" class="rounded-full hover:bg-red-600 bg-red-500 p-2 text-white">
                            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
                                <path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
                                </svg>
                            </button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</div>
<script> 

function toggleSlideover(id) {
    
        document.getElementById('slideover-container').classList.toggle('invisible')
        document.getElementById('slideover-bg').classList.toggle('opacity-0')
        document.getElementById('slideover-bg').classList.toggle('opacity-50')
        document.getElementById('slideover').classList.toggle('translate-x-full')
}
and this is the link I call the slider:
<a href="#" onclick="toggleSlideover()"  wire:click="getOrder({{$id}})" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white btn_payments">Payments</a>

I want to point out that these links are on every row in the table. Does anyone have any idea how to solve my dilemma? I have spent several days to get this working and no matter what I do, I always get the same results. Maybe I can accomplish this using Alpine? I need to be better-versed in Livewire and Alpine.


Solution

  • Since you set this with plain JavaScript, Livewire will not know or keep track of the state of your HTML that was modified by JavaScript. You have two options here,

    1. Add wire:ignore to the slideover, that way Livewire will not overwrite anything during its DOM-diffing phase.
    2. Use Alpine.js to set the state. As this is what Livewire is built upon, it's able to determine the state and preserve it between requests.

    Option 1 is to simply add wire:ignore or wire:ignore.self to your HTML elements, which will prevent Livewire from diffing those elements. This will have other impacts as well, which is why I recommend option 2, using Alpine.js.

    Option 2, uses a single click-event to trigger both the Livewire-call and dispatches an event that opens the slideover.

    <a href="#" x-on:click:="$wire.getOrder({{ $id }}); $dispatch('open-slideover');" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white btn_payments">Payments</a>
    

    Then, on your slideover, use x-data to keep track of the state

    <div 
        id="slideover-container" 
        class="fixed inset-0 w-full h-full invisible z-50"
        x-data="{ open: false }"
        x-on:open-slideover.window="open = true"
        x-bind:class="{ 'invisible': !open }"
    >
        <div 
            onclick="toggleSlideover()" 
            id="slideover-bg" 
            class="absolute duration-500 ease-out transition-all inset-0 w-full h-full bg-gray-900 opacity-0"
            x-bind:class="{ 'opacity-50': open, 'opacity-0': !open' }"
        ></div>
        <div 
            id="slideover" 
            class="absolute w-3/4 duration-500 ease-out transition-all h-full bg-white right-0 top-0"
            x-bind:class="{ 'translate-x-0': open, 'translate-x-full': !open' }"
        >