NigelMcLaughlin's avatar

Dynamically loading modal that has Livewire content

I have a list of phone calls made to a client. I want to click an item in that list, open a modal and fetch the contents of that phonecall.

I can do it by including a modal for every link, but the content for each and every modal is loaded at runtime rather than when the modal.trigger is clicked - this is obviously not a good situation.

I understand you can't load a blade template on the fly as it's a rendered component.

Is there a way of:

  • loading a single instance of the modal html (which has the Livewire directive in it -> or can have the Livewire directive dynamically instantiated?)

  • opening the modal while passing variables to it that can then load a Livewire file with those parameters?

I'm sure there must be a way :-)

0 likes
1 reply
LaryAI's avatar
Level 58

To dynamically load a modal with Livewire content, you can follow these steps to ensure that the modal is only loaded when needed, and the content is fetched dynamically based on the item clicked. Here's a solution using Livewire and Alpine.js:

  1. Create a Livewire Component for the Modal:

    First, create a Livewire component that will handle the display of the phone call details. You can use the artisan command to generate this component:

    php artisan make:livewire PhoneCallDetails
    

    In the PhoneCallDetails component, add a property to hold the phone call details and a method to load the details based on an ID:

    // app/Http/Livewire/PhoneCallDetails.php
    
    namespace App\Http\Livewire;
    
    use Livewire\Component;
    use App\Models\PhoneCall; // Assuming you have a PhoneCall model
    
    class PhoneCallDetails extends Component
    {
        public $phoneCall;
    
        protected $listeners = ['loadPhoneCall'];
    
        public function loadPhoneCall($id)
        {
            $this->phoneCall = PhoneCall::find($id);
        }
    
        public function render()
        {
            return view('livewire.phone-call-details');
        }
    }
    
  2. Create the Blade View for the Livewire Component:

    Create a Blade view for the PhoneCallDetails component. This view will display the details of the phone call:

    <!-- resources/views/livewire/phone-call-details.blade.php -->
    
    <div>
        @if($phoneCall)
            <h2>Phone Call Details</h2>
            <p>Caller: {{ $phoneCall->caller }}</p>
            <p>Time: {{ $phoneCall->time }}</p>
            <p>Notes: {{ $phoneCall->notes }}</p>
        @else
            <p>Loading...</p>
        @endif
    </div>
    
  3. Set Up the Modal and Trigger with Alpine.js:

    Use Alpine.js to handle the modal's visibility and trigger the Livewire event to load the phone call details:

    <!-- resources/views/your-view.blade.php -->
    
    <div x-data="{ showModal: false }">
        <ul>
            @foreach($phoneCalls as $call)
                <li>
                    <a href="#" @click.prevent="showModal = true; $wire.emit('loadPhoneCall', {{ $call->id }})">
                        View Call {{ $call->id }}
                    </a>
                </li>
            @endforeach
        </ul>
    
        <!-- Modal -->
        <div x-show="showModal" @click.away="showModal = false" style="display: none;">
            <div class="modal-content">
                <button @click="showModal = false">Close</button>
                @livewire('phone-call-details')
            </div>
        </div>
    </div>
    
  4. Include Livewire and Alpine.js:

    Make sure you have included Livewire and Alpine.js in your layout:

    <!-- In your main layout file -->
    <head>
        @livewireStyles
        <script src="//unpkg.com/alpinejs" defer></script>
    </head>
    <body>
        @yield('content')
        @livewireScripts
    </body>
    

This setup allows you to dynamically load the modal with the specific phone call details when a list item is clicked. The modal content is fetched only when needed, optimizing performance and resource usage.

Please or to participate in this conversation.