Search code examples
javascripthtml-tablealpine.jslaravel-10

Show address details for clicked row in table using Alpine.js


In table, I have a "View Address" button where when I click, it will show the address details. It works fine but however, since I am still new in Alpine.js, when I click the view address it shows all address details for all rows in the table. Below is my code:

<tbody class="overflow-y-auto" x-data="{ show: false }">
    @foreach ($customer as $customers)
        <tr class="border-b border-gray-200">
            <td class="px-2 py-1 whitespace-nowrap text-xs text-gray-900"></td>
            <td class="px-2 py-1 whitespace-nowrap text-xs text-gray-900">{{ $customers->id }}</td>
            <td class="px-2 py-1 whitespace-nowrap text-xs text-gray-900">{{ $customers->name }}</td>
            <td class="px-2 py-1 whitespace-nowrap text-xs text-gray-900">{{ $customers->email }}</td>
            <td class="px-2 py-1 whitespace-nowrap text-xs text-gray-900">
                <div>
                    <button class="address-button" x-on:click=" show=!show ">View Address</button>
                </div>
            </td>
            <td class="px-2 py-1 whitespace-nowrap text-xs text-gray-900">
                <a href="{{ route('customers.edit', $customers->id) }}"
                    class="text-indigo-600 hover:text-indigo-900"><svg xmlns="http://www.w3.org/2000/svg"
                        width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000"
                        stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34"></path>
                        <polygon points="18 2 22 6 12 16 8 16 8 12 18 2"></polygon>
                    </svg></a>
            </td>
        </tr>
        <tr x-show="show" class="border-b border-gray-200">
            <td class="px-2 py-1 whitespace-nowrap text-xs text-gray-900"></td>
            <td colspan="5" class="px-2 py-1 whitespace-nowrap text-xs text-gray-900">
                @if ($customers->addresses)
                    @php
                        $addresses = is_string($customers->addresses) ? json_decode($customers->addresses, true) : $customers->addresses;
                        $addresses = isset($addresses['addresses']) ? $addresses['addresses'] : $addresses;
                        $num = 1;
                    @endphp
                    @if (!empty($addresses) && is_array($addresses))
                        @foreach ($addresses as $address)
                            <div class="">
                                <strong>Address {{ $num }}</strong><br>

                                @if (array_key_exists('street1', $address))
                                    <strong>Street 1:</strong> {{ $address['street1'] }}<br>
                                @endif
                                @if (array_key_exists('street2', $address))
                                    <strong>Street 2:</strong> {{ $address['street2'] }}<br>
                                @endif
                                @if (array_key_exists('postcode', $address))
                                    <strong>Postcode:</strong> {{ $address['postcode'] }}<br>
                                @endif
                                @if (array_key_exists('city', $address))
                                    <strong>City:</strong> {{ $address['city'] }}<br>
                                @endif
                                @if (array_key_exists('state', $address))
                                    <strong>State:</strong> {{ $address['state'] }}<br>
                                @endif
                                @if (array_key_exists('country', $address))
                                    <strong>Country:</strong> {{ $address['country'] }}<br>
                                @endif
                            </div>
                            @if (!$loop->last)
                                <br>
                            @endif
                            @php
                                $num++;
                            @endphp
                        @endforeach
                    @endif
                @endif
            </td>
        </tr>
    @endforeach
</tbody>

I believe that since I declare <tr x-show="show">, it will show all the address details for all rows. I tried to use based on $customer->id but somehow it does not work.


Solution

  • You have set only one variable show to handle all the rows, so when its value changes all the rows are displayed accordingly

    To fix this without upsetting everything, we can turn the show variable into an array and use the @foreach loop index to access to it, so that each address section has its own show[n] variable (I use a custom variable instead of $loop->index as it is more concise):

    <tbody class="overflow-y-auto" x-data="{ show: Array.from({length: {{ count($customer) }} }, () => false) }">
    
            @foreach ($customer as $rowN => $customers)
    
                <tr>
    
                .....
    
                   <button class="address-button" x-on:click="show[{{$rowN}}] = !show[{{$rowN}}]">View Address</button>
    
                .....
    
                </tr>
     
                <tr x-show="show[{{$rowN}}]" class="border-b border-gray-200">
    
                    .....
    
                    @if ($customers->addresses)
                        .....
                    @endif
    
                    .....
      
                </tr>
    

    Also to avoid the flickering of the hidden rows when the page is rendered, you can add a x-cloak to the address rows:

    <tr x-cloak x-show="show[{{$rowN}}]" class="border-b border-gray-200">