hybridstorm's avatar

Multiple modals on the same page using the same Livewire Component

I am struggling to get this to work so I want to make sure that I am not barking up the wrong tree.

I have a livewire component that has a foreach within it that generates a set of cards that open modals. This component is polling for changes as things are processing on the server side and once they are ready they appear as cards. All of those modals use another Livewire Component that are the same Component to display their content. These also poll when visible as you click around the modal additional processing happens in the background. I mostly have things working but I have a few speed bumps. Most of my issues seem to be tied to DOM diffing issues.

One issue is that the outer Livewire component does not seem to refresh the content of the foreach inner cards unless I reload the page. I can make this work by adding a randomly generated value to the end of the key for each of the items in the foreach. The side effect of this is that, for a reason I don't understand, the modal button stops working until you do a hard refresh. Once refreshed, the buttons work fine. The content of the outer component does not refresh (the modal card changes color after you "finish" it) when you use the random key hack since the key is changing every time livewire polls the page.

I have tried adding and removing "wire:keys" to various elements to make the DOM diffing simpler but I find that usually one thing might get fixed by doing this but something else seems to break. I can post some example code but I wanted to see if there was a better way to do this holistically or if I was on the right track and I just have a bug somewhere that is throwing a wrench in the works.

0 likes
1 reply
LaryAI's avatar
Level 58

One solution to this issue could be to use a unique identifier for each modal instance, such as an ID or a slug. This way, each modal can be uniquely identified and updated without affecting the others.

Another solution could be to use a separate Livewire component for each modal, instead of reusing the same component. This would allow for more granular control over each modal and prevent any potential conflicts between them.

Here is an example of using a unique identifier for each modal instance:

<!-- Outer Livewire component -->
<div>
    @foreach($items as $item)
        <div>
            <button wire:click="$emit('openModal', '{{ $item->id }}')">Open Modal</button>
        </div>
    @endforeach

    <!-- Modal component -->
    <livewire:modal :id="$modalId" />
</div>
// Modal component
class Modal extends Component
{
    public $isOpen = false;

    public function mount($id)
    {
        $this->modalId = $id;
    }

    public function openModal()
    {
        $this->isOpen = true;
    }

    public function closeModal()
    {
        $this->isOpen = false;
    }

    public function render()
    {
        return view('livewire.modal');
    }
}
<!-- Modal view -->
<div wire:ignore.self>
    <div>
        <h2>Modal {{ $modalId }}</h2>
        <button wire:click="closeModal">Close</button>
    </div>
</div>

In this example, each button in the outer component emits an event with a unique identifier for the corresponding modal. The modal component receives this identifier as a prop and uses it to uniquely identify itself. The modal view uses the identifier to display the correct modal content.

Please or to participate in this conversation.