How to use Alpine and Livewire to select multiple records from a paginated data table using checkbox?
I am implementing the functionality of selecting multiple records in a datatable and for this I use Livewire and Alpine together. In the view I use x-model to sync the value of selected checkboxes into an array using Alpine and that array is automatically synced with its corresponding counterpart in the Livewire component via @entangle(). The table records are paginated with Livewire. Everything works fine when the browser loads the livewire component the first time, synchronizing the id of the selected records correctly within the array, but when changing the page of the table using pagination, that's when it starts saving the id twice.
Livewire Component Class:
class IndexUsers extends Component { use WithPagination;
public array $selectedRecords = [];
public int $count_reg = 10;
public function render(): View
{
return view('livewire.admin.users.index-users', [
'usuarios' => User::with('roles')
->notSuperAdmin()
->paginate($this->count_reg),
]);
}
}
Livewire Component View
<table aria-describedby="usuarios_list" class="w-full text-sm text-left text-gray-500" x-data={ selectedRecords: @entangle('selectedRecords'),}>
<thead class="text-xs text-white bg-gray-800 uppercase">
<tr>
<th scope="col" class="px-4 py-3">
<div class="flex items-center">
<input id="checkbox-all-search"
type="checkbox"/>
</div>
</th>
<th scope="col" class="px-4 py-3 cursor-pointer hover:bg-gray-900 whitespace-nowrap"
wire:click="sortBy('username')">
<div class="flex items-center justify-between gap-x-2">
Nombre de usuario
{{-- Sort --}}
<x-colum-sort-icons colum="username"
:sort-by="$sortBy"
:sort-direction="$sortDirection"/>
</div>
</th>
<th scope="col" class="px-4 py-3 cursor-pointer hover:bg-gray-900 whitespace-nowrap"
wire:click="sortBy('name')">
<div class="flex items-center justify-between gap-x-2">
Nombre y Apellidos
{{-- Sort --}}
<x-colum-sort-icons colum="name"
:sort-by="$sortBy"
:sort-direction="$sortDirection"/>
</div>
</th>
<th scope="col" class="px-4 py-3 cursor-default" wire:loading.class.remove="cursor-default">
Roles
</th>
<th scope="col" class="px-4 py-2 cursor-pointer hover:bg-gray-900" wire:click="sortBy('status')">
<div class="flex items-center justify-between" gap-x-2>
Estado
{{-- Sort --}}
<x-colum-sort-icons colum="status"
:sort-by="$sortBy"
:sort-direction="$sortDirection"/>
</div>
</th>
<th scope="col" class="px-4 py-3 cursor-pointer hover:bg-gray-900 whitespace-nowrap"
wire:click="sortBy('created_at')">
<div class="flex items-center justify-between gap-x-2">
Fecha de creación
{{-- Sort --}}
<x-colum-sort-icons colum="created_at"
:sort-by="$sortBy"
:sort-direction="$sortDirection"/>
</div>
</th>
<th scope="col" class="px-4 py-3">
<span class="sr-only">Acciones</span>
</th>
</tr>
</thead>
<tbody>
@forelse ($usuarios as $usuario)
<tr class="bg-white border-b hover:bg-gray-100">
<td class="px-4 py-3">
<div class="flex items-center">
<input id="checkbox-table-{{ $usuario->id }}"
type="checkbox"
value="{{ $usuario->id }}"
x-model="selectedRecords"
:disabled="@js($usuario->isloggedUser())"
:class="@js($usuario->isloggedUser()) && 'cursor-not-allowed'"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 focus:ring-2">
</div>
</td>
<th scope="row" class="px-4 py-3 font-semibold text-gray-900 whitespace-nowrap">
{{ $usuario->username }}
</th>
<td class="px-4 py-3 whitespace-nowrap">
{{ $usuario->name }}
</td>
<td class="px-4 py-3">
<x-colum-badges :array-to-show="$usuario->getRoleNames()->toArray()"/>
</td>
<td class="px-4 py-3">
<x-colum-boolean :boolean-option="$usuario->status"/>
</td>
<td class="px-4 py-3">
{{ $usuario->created_at->translatedFormat('d F Y') }}
</td>
<td class="px-4 py-3">
<div class="flex items-center justify-end gap-x-2">
@can('editar usuarios')
<x-button :href="route('user.edit', [$usuario->id])"
:circle-button="true"
color_button="secondary"
rounded="full"
tooltip="Editar">
<x-phosphor-pencil-simple-bold class="h-3 w-3"/>
</x-button>
@endcan
@can('eliminar usuarios')
<x-button :circle-button="true"
color_button="danger"
rounded="full"
tooltip="Eliminar"
:class="$usuario->isloggedUser() ? 'invisible' : ''"
@click="$dispatch('dialog-confirmation', {
method: 'deleteUser',
params: {{$usuario->id}},
title: 'Eliminar usuario',
message: '¿Está seguro que desea eliminar al usuario {{$usuario->name}}?',
confirmButton: 'Eliminar'
})">
<x-phosphor-trash-bold class="h-3 w-3"/>
</x-button>
@endcan
</div>
</td>
</tr>
@empty
<tr>
<td colspan="7" class="py-12 h4">
<x-empty-data/>
</td>
</tr>
@endforelse
</tbody>
</table>
Please or to participate in this conversation.