achatzi's avatar

Livewire 3 And Bootstrap Popovers

Hello.

I have a livewire 3 component that is basically a table with filters and sorting. For each record I want to show a popover with some info and options.

In my blade file I have

@foreach($rows as $row)
	<tr>
		<td id="userOptions_{{ $row->id }}">
            <button
                wire:key="userOptionsBtn_{{ $row->id }}"
                id="userOptionsBtn_{{ $row->id }}"
                class="btn btn-secondary btn-sm w-100"
                type="button"
                data-bs-toggle="popover"
                data-bs-trigger="focus"
                data-bs-container="#userOptions_{{ $row->id }}"
            >
                <i wire:key="userOptionsLoader_{{ $row->id }}" class="fa-solid fa-cog"></i>
            </button>

			<div wire:key="userOptionsPopover_{{ $row->id }}" id="userOptionsPopover_{{ $row->id }}" class="popover-content">
				<ul class="dropdown-menu">
					<li>
                    	<a href="{{ route('primary-data.users.show', ['user' => $row]) }}" class="dropdown-item text-capitalize"><i class="fa-solid fa-fw fa-search me-1"></i>{{ __('view') }}</a>
                   </li>
    				<li>
        				<a href="{{ route('primary-data.users.edit', ['user' => $row]) }}" class="dropdown-item text-capitalize"><i class="fa-solid fa-fw fa-pencil-alt me-1"></i>{{ __('edit') }}</a>
    				</li>
				</ul>
			</div>
		</td>
	</tr>
@endforeach

In my app.js file I have

function enablePopovers()
{
    for (let popoverTriggerEl of [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))) {
        let options = {};
        let sibling = popoverTriggerEl.nextElementSibling;

        while (sibling) {
            if (sibling.classList.contains('popover-content')) {
                options.html = true;
                options.sanitize = false;
                options.content = sibling.innerHTML;

                break;
            }

            sibling = sibling.nextElementSibling;
        }

        new bootstrap.Popover(popoverTriggerEl, options);
    }
}

document.addEventListener('DOMContentLoaded', () => {
    //enable popovers
    enablePopovers();
});

document.addEventListener('livewire:init', () => {
    Livewire.hook('commit', ({ component, commit, respond, succeed, fail }) => {
        succeed(({ snapshot, effect }) => {
            queueMicrotask(() => {
                if (component.name !== 'generic.notifications') {
                    //enable popovers
                    enablePopovers();
                }
            });
        });
    });
});

The problem I am facing is that the popovers are not working properly. When you first enter the page everything is ok, when you try to sort or filter (so livewire refreshes), the popovers stop working. What is more weird is that if after the sorting or filtering, a row does not change position the popover still works. But even that is not consistent because I had I few cases that it did not work.

I have a console log in my js functions so I know they are being called, but the popovers are not working.

I tried to dispose the popovers and enable them again

function disposePopovers()
{
    for (let popoverTriggerEl of [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))) {
        let popover = bootstrap.Popover.getOrCreateInstance(popoverTriggerEl);

        popover.dispose();
    }
}

Livewire.hook('commit.prepare', ({ component, commit }) => {
    if (component.name !== 'generic.notifications') {
        //dispose popovers
        disposePopovers();
    }
});

but that did not work either.

Any ideas anyone? This is driving me nuts!

0 likes
0 replies

Please or to participate in this conversation.