I have a table that displays matching rows between 2 datasets. The rows that have a match will have a "subrow", so when you click the row, the matched data will show in the subrow. This works totally fine except...
I also have a checkbox in the table header that shows/hides a subset of the rows in the table. The table also has pagination. Anytime you use the pagination, or you check the checkbox to hide rows (or basically perform any action that sends an ajax request), some of the remaining rows that are shown no longer register the click event when you click them.
I've gone through the troubleshooting steps here , and it feels like a dom diffing issue, but I can't figure out what's going on.
I've also added wire:ignore
and/or wire:ignore.self
to try and get it to work right, but just isn't cooperating.
Here's the jquery that's fired when you click a table row:
@pushonce('custom-scripts')
<script>
$('.table-row').on('click', function(el) {
console.log('row clicked'); <--works until you paginate or click checkbox
let row = $(this).closest('tr');
if (row.hasClass('has-match')) {
let id = row.attr('id').split('-')[2];
if ($('#tx-subrow-' + id).hasClass('d-none')) {
$('#tx-identified-subrow-' + id).removeClass('d-none');
$('#tx-subrow-' + id).removeClass('d-none');
} else {
$('#tx-identified-subrow-' + id).addClass('d-none');
$('#tx-subrow-' + id).addClass('d-none');
}
}
});
</script>
@endpushonce
The checkbox essentially removes exact matches from the table, so you're left with partial matches (have a subrow), and non-matches (don't have a subrow). In my current testing data, after clicking the checkbox, the rows above the first row that has a subrow all register the click event, but starting with the row with a subrow, it no longer registers. This image will hopefully help it make more sense:
Everything functions normally until you paginate or click the checkbox, and then I get this weird behavior.
Here's a simplified version of the tr
element that's in a forelse
loop in my blade file:
<tr wire:key="tx-row-{{ $tx->id }}" id="tx-row-{{ $tx->id }}" role="{{ !empty($tx->transaction_id) ? 'button' : '' }}" class="table-row {{ $tx->has_match && !$tx->match_removed ? 'has-match bg-light' : '' }} {{ $tx->has_partial_match && !$tx->match_removed ? 'has-match bg-white' : '' }}"
style="--bs-bg-opacity: .50;">
<td>... </td>
<tr id="tx-subrow-{{ $tx->id }}" wire:key="tx-subrow-{{ $tx->id }}" class="bg-dark d-none" style="--bs-bg-opacity: .20;">
<td>...</td>
</tr>
<span>
@if ($tx->has_identified_match)
<tr id="tx-identified-subrow-{{ $tx->id }}" wire:key="tx-identified-subrow-{{ $tx->id }}" class="bg-dark d-none" style="--bs-bg-opacity: .20;">
<td colSpan="9">
...
</tr>
@endif
</span>
</tr>
Here's the render method in my livewire component:
public function render()
{
return view('livewire.vendors.statement-reconcile', [
'transactions' => $this->getTransactions(),
]);
}
and here's the getTransactions()
method:
public function getTransactions()
{
if ($this->excludeFullMatches) {
return StatementTransaction::search($this->search)->where('statement_id', $this->statement->id)->query(function ($query) {
$query->where(function ($q) {
$q->where('has_match', false)
->orWhere('has_partial_match', true)
->orWhere('match_removed', true);
});
})->paginate($this->rowsPerPage);
} else {
return StatementTransaction::search($this->search)->where('statement_id', $this->statement->id)
->paginate($this->rowsPerPage);
}
}
Wondering if those could potentially be the problem, but taking the checkbox out of the equation, it still breaks just when using pagination, so not sure the getTransactions()
method is the issue.
I've made sure I only have a single root div element. I've wrapped all my blade conditionals in an element. I'm stumped as to why this isn't working.
UPDATE
After digging a bit further, I found that if I use the search field to search for a record that's on the initial page of results when the page first loads, then that row will expand out as intended. If I search for a record that's on another page of results, then it won't register the click event. Very strange behavior, but it seems like it has something to do with the pagination.
Nothing strange here, your
$('.table-row').on('click', function(el) {...})
line takes you rows that are on the page and adds event listeners to them. All of your new rows from ajax doesn't have that event listeners so clicks aren't working. Just change this line to this:
$(document).on('click', '.table-row', function(el) {