Laravel and Alpinejs : Creating List Data and Modal with Data Based on Index

Laravel and Alpinejs : Creating List Data and Modal with Data Based on Index

·

3 min read

image.png

On this occasion I want to share about how I create a popup with dynamic data based on a certain index in a laravel and alpinejs project.

Immediately, for example we have product data, In controller, we pass data from model to views app.

        return view('app', [
            'products' => Product::isPublished(0)->get()            
        ]);

Then on the blade app page, we convert the collection model to json like this.

    @php 
        $products = $products->toJson();
    @endphp

That way we can set the state value with the json.

<body x-data="{ products : {{ $products }}, detailData : '' }">

    -----
    -----
</body>

Based on the above code, we have defined two state products and detailData. detailData is useful for storing data based on a certain index used in the modal component.

Next we will make a list of products, the code is like this.

 <div class="divide-y mt-5">
    <template x-for="(product,i) in products" :key="product.id">
        <div class="flex flex-row w-full px-6 py-6 mx-auto  bg-white  rounded-lg sm:px-4  sm:py-5">
            <div class="ml-2 mr-4">
                <a href="#" type="button" @click="detailData = products[i]"  data-modal-toggle="defaultModal">
                    <img class="rounded-lg" src="https://storage.googleapis.com/public-listee-menu-items/77_eb66ceac-7d52-443e-b96a-d2ee1db522b1_thumbnail.png" alt="product image" />
                </a>
            </div>
            <div>
                <h3 class="text-lg font-bold text-purple-500 sm:text-xl md:text-2xl" x-text="product.name"></h3>
                <p class="mt-2 text-base text-gray-400 sm:text-sm md:text-normal" x-text="product.description"></p>
                <p class="mt-2 text-base font-semibold text-gray-700 sm:text-lg md:text-normal" x-text="product.price"></p>
            </div>
        </div>
    </template>
</div>

A little explanation, in the code above we iterate the data using x-for alpinejs.

x-for="(product,i) in products" :key="product.id"

Then set the text using x-text

Then we also have the directive @click="detailData = products[i]", which assigns a value to the detailData variable when clicked, so detailData now has data based on the index clicked.

Modal

image.png

<div id="defaultModal" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed right-0 left-0 top-4 z-50 justify-center items-center h-modal md:h-full md:inset-0">
    <div class="relative px-4 w-full max-w-2xl h-full md:h-auto">
        <!-- Modal content -->
        <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
            <!-- Modal header -->
            <div class="flex justify-between items-start p-3 rounded-t border-b dark:border-gray-600">
                <h3 class="text-xl font-semibold text-gray-900 lg:text-2xl dark:text-white">
                    Menu Item
                </h3>
                <button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-toggle="defaultModal">
                    <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>  
                </button>
            </div>
            <!-- Modal body -->
            <div class="p-3 space-y-6">
                <div class="divide-y">
                    <div class="flex flex-row w-full px-6 py-3 mx-auto  bg-white  rounded-lg sm:px-4  sm:py-5   ">
                        <div class="ml-2 mr-4">
                            <a href="#" type="button" data-modal-toggle="defaultModal">
                                <img class="rounded-lg" src="https://storage.googleapis.com/public-listee-menu-items/77_eb66ceac-7d52-443e-b96a-d2ee1db522b1_thumbnail.png" alt="product image" />
                            </a>
                        </div>
                        <div>
                            <h3 class="text-lg font-bold text-purple-500 sm:text-xl md:text-1xl" x-text="detailData.name"></h3>
                            <p class="text-base text-gray-400 sm:text-sm md:text-normal" x-text="detailData.description"></p>
                            <p class="text-base font-semibold text-gray-700 sm:text-lg md:text-normal" x-text="detailData.price"></p>
                        </div>
                    </div>
                </div>
                <div class="px-6 mb-2">
                    <label for="large-input" class="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300">Special Instructions (Optional)</label>
                    <textarea type="text" id="large-input" placeholder="food description" class="block p-4 w-full text-gray-900 bg-gray-50 rounded-lg border border-gray-300 sm:text-md focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"></textarea>
                </div>
                <div class="flex items-center justify-center p-6 space-x-2 rounded-b border-t border-gray-200 dark:border-gray-600">
                    <button data-modal-toggle="defaultModal" type="button" class="text-black text-2xl  bg-gray-200 hover:bg-gray-400 focus:ring-4 focus:ring-blue-300 font-medium rounded-full text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">-</button>
                    <p class="px-6 text-base leading-relaxed text-gray-500 font-bold text-2xl dark:text-gray-400">8</p>
                    <button data-modal-toggle="defaultModal" type="button" class="text-black  text-2xl text-center bg-gray-200 hover:bg-gray-400 focus:ring-4 focus:ring-blue-300 font-medium rounded-full text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">+</button>
                </div>
            </div>
            <!-- Modal footer -->
            <div class="flex justify-center items-center p-6 space-x-2 rounded-b border-t border-gray-200 dark:border-gray-600">
                <button data-modal-toggle="defaultModal" type="button" class="w-full h-12 px-6 text-indigo-100 transition-colors duration-150 bg-indigo-700 rounded-lg focus:shadow-outline hover:bg-indigo-800">Add to Order - Rp. 85,000</button>
            </div>
        </div>
    </div>
</div>

In the modal, we set the text by x-text="detailData.name".

That's the steps hopefully useful. Thank You