skip to Main Content

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.

enter image description here

2

Answers


  1. Keying Livewire components requires :key instead of wire:key as shown in the docs:

    <livewire:user.user-row :key='{{ $user->id }}' :user="$user" :iteration="$loop->iteration" @user_deleted="$refresh" />
    
    Login or Signup to reply.
  2. Remove the :iteration="$loop->iteration" part from the UserRow component call and adjust the row count display in your parent component’s Blade file.

    @foreach ($users as $index => $user)
        <livewire:user.user-row wire:key='{{ $user->id }}' :user="$user" 
            :rowNumber="$users->firstItem() + $index" @user_deleted="$refresh" />
    @endforeach
    

    Add a public property in your UserRow component to accept this value.

    public $rowNumber;
    

    And use the rowNumber property:

    <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">
            {{ $rowNumber }}
        </td>
    </tr>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search