I want to display the row count from the result of the pagination. It works well from the initial page load, however if I add new record, the table component will refresh however the row counter from the @foreach
is not changed. How change it?
<?php
namespace AppLivewireUser;
use AppModelsUser;
use LivewireComponent;
use LivewireWithPagination;
class Users extends Component
{
use WithPagination;
public $search = "";
public $sortCol = "id";
public $sortAsc = false;
public function sortBy($column)
{
if ($this->sortCol == $column) {
$this->sortAsc = !$this->sortAsc;
} else {
$this->sortAsc = true;
}
$this->sortCol = $column;
}
protected function applySorting($query)
{
if ($this->sortCol) {
$query->orderBy($this->sortCol, $this->sortAsc ? 'asc' : 'desc');
}
return $query;
}
protected function applySearch($query)
{
if ($this->search) {
$query->where('name', 'like', '%' . $this->search . '%')
->orWhere('email', 'like', '%' . $this->search . '%');
}
return $query;
}
public function updatingSearch()
{
$this->resetPage();
}
public function render()
{
$usersQuery = User::query();
$this->applySearch($usersQuery);
$this->applySorting($usersQuery);
$users = $usersQuery->paginate(10);
return view('livewire.user.users', ['users' => $users]);
}
}
<div>
<div class="relative p-5 overflow-x-auto bg-white shadow-md sm:rounded-lg">
<div class="pb-4 bg-white dark:bg-gray-900">
<label for="table-search" class="sr-only">Search</label>
<div class="relative flex items-start justify-between mt-1">
<livewire:user.add-user-dialog @added="$refresh" />
<div class="relative">
<input wire:model.live.debounce.500='search' readonly type="text" id="table-search"
class="block w-full pt-2 text-sm text-gray-900 border border-gray-300 rounded-lg md:w-64 ps-10 bg-gray-50 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"
placeholder="Search for items">
<svg class="absolute w-4 h-4 text-gray-500 transform -translate-y-1/2 top-1/2 left-3 dark:text-gray-400"
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" />
</svg>
</div>
</div>
</div>
<div class="relative">
<table class="w-full text-sm text-left text-gray-500 rtl:text-right dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th class="px-6 py-3">#</th>
<th scope="col" class="px-6 py-3">
<x-table.header column="name" :$sortCol :$sortAsc>
<div>Name</div>
</x-table.header>
</th>
<th scope="col" class="px-6 py-3">
<x-table.header column="email" :$sortCol :$sortAsc>
<div>Email</div>
</x-table.header>
</th>
<th scope="col" class="px-6 py-3">
<x-table.header column="created_at" :$sortCol :$sortAsc>
<div>Date Created</div>
</x-table.header>
</th>
<th>
</th>
</tr>
</thead>
<tbody>
@foreach ($users as $user)
<livewire:user.user-row wire:key='{{ $user->id }}' :user="$user" :iteration="$loop->iteration"
@user_deleted="$refresh" />
@endforeach
</tbody>
</table>
<div wire:loading class="absolute inset-0 bg-white opacity-50">
</div>
<div wire:loading.flex class="absolute inset-0 flex items-center justify-center">
<x-icon.spinner size="8" class="text-gray-500" />
</div>
</div>
<div class="pt-4">
</div>
{{-- Pagination... --}}
<div class="flex items-center justify-between pt-4">
<div class="text-sm text-gray-700">
@php
$start = ($users->currentPage() - 1) * $users->perPage() + 1;
$end = min($start + $users->perPage() - 1, $users->total());
@endphp
Showing {{ $start }} to {{ $end }} of {{ $users->total() }}
</div>
{{ $users->links() }}
</div>
</div>
</div>
<?php
namespace AppLivewireUser;
use AppLivewireFormsUserUserForm;
use AppModelsUser;
use LivewireAttributesOn;
use LivewireComponent;
class UserRow extends Component
{
public $user;
public $iteration;
public UserForm $form;
public $showEditDialog = false;
public function mount()
{
$this->form->setUser($this->user);
}
public function save()
{
$this->form->update();
$this->reset('showEditDialog');
$this->user->refresh();
$this->dispatch('user_updated');
}
#[On('added')]
public function reloadTable()
{
$this->reset('iteration');
}
public function delete(User $user)
{
$user->delete();
$this->dispatch('user_deleted');
}
public function render()
{
return view('livewire.user.user-row');
}
}
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
<td class="px-2 py-2">
{{-- display the current row count ex 16 to 15 --}}
{{-- {{ $loop->iteration + $users->perPage() * ($users->currentPage() - 1) }} --}}
{{ $iteration }}
</td>
<td class="px-2 py-2">
{{ $user->name }}
</td>
<td class="px-2 py-2">
{{ $user->email }}
</td>
<td class="px-2 py-2">
{{ $user->created_at->format('M d, Y') }}
</td>
<td class="flex justify-end gap-2 py-4 pl-4 pr-6 text-right">
<x-menu>
<x-menu.button>
<x-icon.ellipsis class="w-6 h-6" />
</x-menu.button>
<x-menu.items>
<x-dialog wire:model="showEditDialog">
<x-dialog.open>
<x-menu.close>
<x-menu.item>
<x-icon.pencil class="w-4 h-4" />
Edit
</x-menu.item>
</x-menu.close>
</x-dialog.open>
<x-dialog.panel>
<form wire:submit='save'>
<h2 class="mb-1 text-2xl font-bold">Update User</h2>
<hr class="mb-5">
<div class="mb-5">
<label class="block mb-2 text-sm font-bold text-gray-900 dark:text-white">Name</label>
<input autofocus wire:model='form.name' type="text" name="name"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 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"
placeholder="Nerison S. Pitogo">
@error('form.name')
<div class="text-sm font-normal text-red-500">
{{ $message }}</div>
@enderror
</div>
<div class="mb-5">
<label class="block mb-2 text-sm font-bold text-gray-900 dark:text-white">Email</label>
<input wire:model='form.email' type="email" name="email"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 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"
placeholder="[email protected]">
@error('form.email')
<div class="text-sm font-normal text-red-500">
{{ $message }}</div>
@enderror
</div>
<div class="mb-5">
<label
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Password</label>
<input wire:model='form.password' type="password" name="password"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 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">
@error('form.password')
<div class="text-sm font-normal text-red-500">
{{ $message }}</div>
@enderror
</div>
<x-dialog.footer>
<x-dialog.close>
<button type="button"
class="px-6 py-2 font-semibold text-center rounded-xl bg-slate-300 text-slate-800">Cancel</button>
</x-dialog.close>
<button wire:confirm="Are you sure?" type="submit"
class="inline-flex items-center py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg px-7 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
<x-icon.add_user class="w-5 h-5 mr-2" />
Save New User
</button>
</x-dialog.footer>
</form>
</x-dialog.panel>
</x-dialog>
<x-menu.close>
<x-menu.item wire:confirm='Are you sure?' wire:click='delete({{ $user->id }})'>
<div class="flex items-center justify-center text-red-600">
<x-icon.trash class="w-4 h-4 mr-1" />
Delete
</div>
</x-menu.item>
</x-menu.close>
</x-menu.items>
</x-menu>
</td>
</tr>
Initally the table looks good. But after adding new records. Here is what happened. Duplicate row number 1.
2
Answers
Keying Livewire components requires
:key
instead ofwire:key
as shown in the docs:Remove the
:iteration="$loop->iteration"
part from theUserRow
component call and adjust the row count display in your parent component’s Blade file.Add a public property in your
UserRow
component to accept this value.And use the
rowNumber
property: