Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

gabriel27's avatar

Multiple modals on one page - correct option to implement

Hello,

I have a page with multiple entries displayed in sections and sub sections. In each section and subsection I have buttons that trigger a modal form.

I used the Filament 3 section blade component: https://filamentphp.com/docs/3.x/support/blade-components/section and the modal component with an external button: https://filamentphp.com/docs/3.x/support/blade-components/modal

I made only one option that works: for each entry call a livewire component that will show a form specific to that entry:

   @foreach($this->product->category as $category)
    <x-filament::section collapsible>
        <x-slot name="heading">
            <div class="fi-header flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
                {{ $category->name }}
            </div>
        </x-slot>
        <x-slot name="headerEnd">
            <x-filament::button icon="heroicon-o-pencil-square" color="info" class="float-right" x-on:click="$dispatch('open-modal',{ id: 'edit-category-{{ $this->product->id }}-{{$category->id}}' })">
                Edit category
            </x-filament::button>
            <x-filament::button icon="heroicon-o-plus-circle" color="success" class="float-right" x-on:click="$dispatch('open-modal',{ id: 'edit-subcategory-{{ $this->product->id }}-{{$category->id}}-' })">
                Add SubCategory
            </x-filament::button>

            @livewire('products.add-edit-category',['action_text'=>'Edit','product'=> $this->product,'category'=>$category], key('edit-category-'.$this->product->id.'-'.$category->id));
            @livewire('products.add-edit-subcategory',['action_text'=>'Add','product'=> $this->product,'category'=>$category], key('edit-subcategory-'.$this->product->id.'-'.$category->id.'-'))

    </x-filament::section>
    @endforeach
    <x-filament-actions::modals />

If I have a lot of categories the page will load very slow as Livewire will load all components on load.

If I set Lazy load by setting #[Lazy] before the components class definition it will load the buttons on load but nothing will happen until that component is loaded, which makes sense.

I I encapsulate the @livewire request for each component in an if the modal will not activate as I believe it is not loaded when the DOM is created (I believe).

What I believed to be correct is to request the 2 livewire components EditCategory and EditSubcategory only once outside the foreach and depending on the button clicked to get the parameters and populate each form.

I want to mention that the category and subcategory are different models with different properties and different forms.

Thanks.

0 likes
2 replies
LaryAI's avatar
Level 58

Hello,

It seems you're facing a performance issue due to the instantiation of multiple Livewire components for each category and subcategory. To optimize this, you can indeed use a single instance of each Livewire component and dynamically update its state based on the user's interaction.

Here's a potential solution:

  1. Create two Livewire components: one for editing categories (EditCategory) and one for adding subcategories (AddSubcategory).
  2. In your Blade template, place these components outside of the foreach loop.
  3. Use JavaScript to update the state of the Livewire components when a button is clicked.

Here's an example of how you might implement this:

@foreach($this->product->category as $category)
    <x-filament::section collapsible>
        <x-slot name="heading">
            <div class="fi-header flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
                {{ $category->name }}
            </div>
        </x-slot>
        <x-slot name="headerEnd">
            <x-filament::button icon="heroicon-o-pencil-square" color="info" class="float-right" wire:click="$emit('editCategory', {{ $category->id }})">
                Edit category
            </x-filament::button>
            <x-filament::button icon="heroicon-o-plus-circle" color="success" class="float-right" wire:click="$emit('addSubcategory', {{ $category->id }})">
                Add SubCategory
            </x-filament::button>
        </x-slot>
    </x-filament::section>
@endforeach

@livewire('products.edit-category')
@livewire('products.add-subcategory')

<x-filament-actions::modals />

In your Livewire components (EditCategory and AddSubcategory), listen for the emitted events and update the component's state accordingly:

// In EditCategory.php
protected $listeners = ['editCategory' => 'loadCategory'];

public function loadCategory($categoryId)
{
    // Load the category model and update the component's state
    $this->category = Category::find($categoryId);
    // Open the modal
    $this->dispatchBrowserEvent('open-modal', ['id' => 'edit-category-modal']);
}

// In AddSubcategory.php
protected $listeners = ['addSubcategory' => 'prepareForSubcategory'];

public function prepareForSubcategory($categoryId)
{
    // Prepare the component to add a subcategory to the given category
    $this->category = Category::find($categoryId);
    // Open the modal
    $this->dispatchBrowserEvent('open-modal', ['id' => 'add-subcategory-modal']);
}

Make sure to define the modals in your Livewire components' Blade templates and use the dispatchBrowserEvent method to trigger the modal opening.

This approach will ensure that only one instance of each component is used, and it will dynamically load the necessary data when the user interacts with the buttons. This should significantly improve the performance of your page.

gabriel27's avatar

Unfortunately the above does not work. Any other suggestions?

Please or to participate in this conversation.