F
Filament3mo ago
CT

Correct way to add/create a Livewire table column component?

I have a table that when clicked opens a modal and runs some calculations. The calculations are expensive so I do not want to do them until the button is clicked. I have a working solution, but the problem is it will break when switching views with errors such as: Snapshot missing on Livewire component with id: R1rsgkBVrClAl8P8eYzL" The code I have is as follows;
Tables\Columns\TextColumn::make('score_100')
->label(__('Score 100'))
->state(function (Site $site) {
if (!$site->score_100) {
return null;
}

return new HtmlString(view('components.score', [
'site' => $site,
'score' => $site->score_100
])->render());
}),
Tables\Columns\TextColumn::make('score_100')
->label(__('Score 100'))
->state(function (Site $site) {
if (!$site->score_100) {
return null;
}

return new HtmlString(view('components.score', [
'site' => $site,
'score' => $site->score_100
])->render());
}),
and components.score looks like this:
<livewire:score-modal :siteId="$site->id" :score="$score" :key="$site->id . '-modal-' . $score">

</livewire:score-modal>
<livewire:score-modal :siteId="$site->id" :score="$score" :key="$site->id . '-modal-' . $score">

</livewire:score-modal>
The livewire score modal looks like this:
<div :key="container-{{ $siteId }}">
<button wire:click="openModal({{ $siteId }})" class="cursor-pointer">
{{ $score }}
</button>

@if (isset($selectedSite))
<x-filament::modal
width="4xl"
id="score-modal-{{ $selectedSite->id . '-' . $score }}">
... rest of the modal
<div :key="container-{{ $siteId }}">
<button wire:click="openModal({{ $siteId }})" class="cursor-pointer">
{{ $score }}
</button>

@if (isset($selectedSite))
<x-filament::modal
width="4xl"
id="score-modal-{{ $selectedSite->id . '-' . $score }}">
... rest of the modal
And all the calculations happen within the /app/Livewire/ScoreModal.php component... As I mentioned before everything is working but I keep getting these livewire errors. I've tried adding :key or wire:key to wherever possible but it seems to make no difference. I'm probably missing something obvious/simple here?
1 Reply
CT
CT3mo ago
Ok I managed to find a solution which works and gives no livewire key errors. It's kinda hacky, so if anyone can tell me the proper way it would be appreciated. What I ended up doing is keeping the TextColumn as is, then making an Action and calling that action. Like this:
Tables\Columns\TextColumn::make('score_100')
->label(__('Score 100'))
->disabledClick()
->state(function (Site $site) {
if (!$site->score_100) {
return null;
}

return new HtmlString(view('components.score', [
'siteId' => $site->id,
'score' => $site->score_100
])->render());
}),
Tables\Columns\TextColumn::make('score_100')
->label(__('Score 100'))
->disabledClick()
->state(function (Site $site) {
if (!$site->score_100) {
return null;
}

return new HtmlString(view('components.score', [
'siteId' => $site->id,
'score' => $site->score_100
])->render());
}),
inside components.score :
<button wire:click="mountTableAction('score-modal', '{{ $siteId }}')" class="cursor-pointer">
{{ $score }}
</button>
<button wire:click="mountTableAction('score-modal', '{{ $siteId }}')" class="cursor-pointer">
{{ $score }}
</button>
and finally the action like this:
Tables\Actions\Action::make('score-modal')
->extraAttributes(['class' => 'hidden'])
->modalContent(fn ($record): View => view(
'livewire.score-modal',
['site' => $record],
))
Tables\Actions\Action::make('score-modal')
->extraAttributes(['class' => 'hidden'])
->modalContent(fn ($record): View => view(
'livewire.score-modal',
['site' => $record],
))
I tried to directly call ->action('score-modal') on the TextColumn, but it would return an error saying that score-modal doesn't exist on ListSites (my filament resource).