Dropdown with auto position using Tailwindcss and Flowbite

59 views Asked by At

I have a table with paginations and each row has a button that when pressed, a dropdown menu shows up. Works fine. Each page has 10 rows. I click the next page and that page has let's say 9 rows. When I go to the previous page which has 10 rows, the 10th row button's dropdown no longer works and the other 9 work. Same thing will happen if the next page has 8 rows going back to the page that has 10 rows, the 8th and 9th button's dropdown no longer work.

<table>
<?php $counter = 0;?>
@foreach ($products as $product)
<?php $counter ++;?>
<tr>
    <td>
        <div>
            <button  data-dropdown-toggle="dropdownAction_{{ $counter }}" 
                class="inline-flex items-center text-gray-500 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 font-medium rounded-lg text-sm px-3 py-1.5 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700 actionButton" type="button">
                <span class="sr-only">Show</span>
                Action
                <svg class="w-2.5 h-2.5 ms-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
                    <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
                </svg>
            </button>
            <!-- Dropdown menu -->
            <div id="dropdownAction_{{ $counter }}" class="z-10 hidden bg-gray-200 divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700 dark:divide-gray-600 actionMenu">
                <ul class="py-1 text-sm text-gray-700 dark:text-gray-200">
                    <li>
                        <a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Print Invoice</a>
                    </li>
                    <li>
                        <a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Print Statement</a>
                    </li>
                    <li>
                        <a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Print Commercial</a>
                    </li>
                    <li>
                        <a href="#" class="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">Print Appraisal</a>
                    </li>
                </ul>
                <div class="py-1">
                    <a href="#" 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">Email Invoice</a>
                </div>
                <div class="py-1">
                    <a href="#" 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">Payments</a>
                </div>
            </div> 
        </div>
    </td>
    <td>....</td>
    <td>....</td>
    <td>....</td>
    <td>....</td>
</tr>
@endforeach
1

There are 1 answers

2
Pippo On

When you display data with loops in Livewire you must add an unique wire-key to each "row" to let the engine manage properly the changes when the HTML rows are modified.

@foreach ($products as $product)
    <?php $counter ++;?>
    <tr wire:key="prod-{{ $product->id }}">
       
    .....
@endforeach

You could also use id instead of the counter variable, but not the other way around because wire:key must be absolutely unique across the pagination.

Edit

You are using a Flowbite component that uses some custom javascript code to automate the elements interaction.

Now, using wire:key, Livewire can correctly update the page when paginating, but since the rows are replaced, the event listeners placed by Flowbite are lost.

My first suggestion is to abandon the Flowbite code and manage the interaction of the elements with AlpineJs that is already included in Livewire.

But, to save your work, we can try to re-init the Flowbite events after the Livewire code has replaced the DOM's elements.
A possible solution can be to find an element that is updated after the table rows, the paginator is a good candidate:

<div>
     <table>
        .....
     </table>

     <div id="paginator">
        {{ $products->links() }}
    </div>
</div>       

<script>
    document.addEventListener("livewire:init", () => {

        Livewire.hook('morph.updated', ({ el, component }) => {

            if (el.id == "paginator") {
                initFlowbite();  // <--- this reinitialize the event listeners
            }
        });
    });
</script>

you can find other similar solutions here and here, choose the one that best suits you.