I'm building a table with a select on each row, and a "Select All" Option, with Laravel and Livewire, currently, it works but, my records are paginated, say for example, page 1 shows records 1 through 6, and page 2, records from 7 through 12.
If I select on the first page, records 1 and 2, ( rows 1 and 2 ), and then go to page 2, the checkboxes for rows 1 and 2 are checked. How can I fix it so that, when I paginate, the rows whose records I haven't selected are not checked?
<div class="table-container">
<table class="table">
<thead>
<tr>
<th>
<input type="checkbox" class="sales-checkbox" wire:model.live="selectAll"/>
</th>
<th>Número</th>
<th>Cliente</th>
<th>Creación</th>
<th>Vencimiento</th>
<th>Total</th>
<th>Por Cobrar</th>
<th>Estado</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
@foreach($invoices as $invoice)
<tr>
<th class="whitespace-nowrap align-content-center align-items-center text-center">
@if($invoice->trashed())
-
@else
<input type="checkbox" class="sales-checkbox" wire:model.live="selected"
@if(in_array($invoice->id, $selected)) checked @endif
value="{{ $invoice->id }}"/>
@endif
</th>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->invoice_number }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->customer->name }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->created_at->format('d/m/Y') }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->expiration_date->format('d/m/Y') }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">C$ {{ \Illuminate\Support\Number::format($invoice->total_amount) }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">C$ {{ \Illuminate\Support\Number::format($invoice->total_amount - $invoice->payments->sum('amount_in_nio')) }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">
@if($invoice->trashed())
<x-jemg-components.invoice-status-badges
type="danger"
text="Anulada">
</x-jemg-components.invoice-status-badges>
@else
<x-jemg-components.invoice-status-badges
type="{{ $invoice['status_labels']['type'] }}"
text="{{ $invoice['status_labels']['label'] }}">
</x-jemg-components.invoice-status-badges>
@endif
</td>
<td class="whitespace-nowrap align-content-center align-items-center">
<x-jemg-components.flat-actions
:show="route('admin.sales.show',$invoice)"
:export="route('admin.sales.export',$invoice)"
:model="$invoice"
:trashed="$invoice->trashed()"
/>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
Component Class:
class SalesIndex extends Component
{
use WithPagination;
public $selected = [];
public $selectAll = false;
public function render()
{
$invoices = Invoice::query()
->with(['customer', 'user', 'subProducts', 'payments'])
->latest('id')
->withTrashed()
->paginate(50);
return view('livewire.sales.sales-index', compact('invoices'));
}
public function updatedSelectAll($value)
{
if ($value) {
$this->selected = Invoice::pluck('id')->map(fn ($id) => (string) $id)->toArray();
} else {
$this->selected = [];
}
}
}
I'm building a table with a select on each row, and a "Select All" Option, with Laravel and Livewire, currently, it works but, my records are paginated, say for example, page 1 shows records 1 through 6, and page 2, records from 7 through 12.
If I select on the first page, records 1 and 2, ( rows 1 and 2 ), and then go to page 2, the checkboxes for rows 1 and 2 are checked. How can I fix it so that, when I paginate, the rows whose records I haven't selected are not checked?
<div class="table-container">
<table class="table">
<thead>
<tr>
<th>
<input type="checkbox" class="sales-checkbox" wire:model.live="selectAll"/>
</th>
<th>Número</th>
<th>Cliente</th>
<th>Creación</th>
<th>Vencimiento</th>
<th>Total</th>
<th>Por Cobrar</th>
<th>Estado</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
@foreach($invoices as $invoice)
<tr>
<th class="whitespace-nowrap align-content-center align-items-center text-center">
@if($invoice->trashed())
-
@else
<input type="checkbox" class="sales-checkbox" wire:model.live="selected"
@if(in_array($invoice->id, $selected)) checked @endif
value="{{ $invoice->id }}"/>
@endif
</th>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->invoice_number }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->customer->name }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->created_at->format('d/m/Y') }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">{{ $invoice->expiration_date->format('d/m/Y') }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">C$ {{ \Illuminate\Support\Number::format($invoice->total_amount) }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">C$ {{ \Illuminate\Support\Number::format($invoice->total_amount - $invoice->payments->sum('amount_in_nio')) }}</td>
<td class="whitespace-nowrap align-content-center align-items-center">
@if($invoice->trashed())
<x-jemg-components.invoice-status-badges
type="danger"
text="Anulada">
</x-jemg-components.invoice-status-badges>
@else
<x-jemg-components.invoice-status-badges
type="{{ $invoice['status_labels']['type'] }}"
text="{{ $invoice['status_labels']['label'] }}">
</x-jemg-components.invoice-status-badges>
@endif
</td>
<td class="whitespace-nowrap align-content-center align-items-center">
<x-jemg-components.flat-actions
:show="route('admin.sales.show',$invoice)"
:export="route('admin.sales.export',$invoice)"
:model="$invoice"
:trashed="$invoice->trashed()"
/>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
Component Class:
class SalesIndex extends Component
{
use WithPagination;
public $selected = [];
public $selectAll = false;
public function render()
{
$invoices = Invoice::query()
->with(['customer', 'user', 'subProducts', 'payments'])
->latest('id')
->withTrashed()
->paginate(50);
return view('livewire.sales.sales-index', compact('invoices'));
}
public function updatedSelectAll($value)
{
if ($value) {
$this->selected = Invoice::pluck('id')->map(fn ($id) => (string) $id)->toArray();
} else {
$this->selected = [];
}
}
}
Share
asked Mar 10 at 10:56
Jarliev PérezJarliev Pérez
2621 gold badge8 silver badges21 bronze badges
1 Answer
Reset to default 0You must use a unique wire:key when displaying data in a loop. The record ID is a good option, but it's best to also add a prefix to avoid conflicts when displaying multiple resources with the same ID on the same page.
The wire:key lets Livewire know which HTML elements have changed when merging the new rendered HTML with the currently displayed HTML.
@foreach($invoices as $invoice)
<tr wire:key="invoice-{{ $invoice->id }}">
....
Here you can find documentation about this behavior