I am currently making a web page with a place where users can add subreddits to a list, when they do it on first page load when there are 0 subreddits all goes perfectly fine and they can add as many as they want without any issue. Then when the user reloads the page and they try to add more, the following error pops up:
Uncaught Snapshot missing on Livewire component with id
I have tried to remedy this with adding keys to the elements in the foreach, but alas no improvement. I’ve been searching for a fix but I have yet to find anything and thus I’d love some help with resolving the issue!
subreddit-bar.blade.php
@php use AppSupportReddit; @endphp
<div
class="w-1/3 rounded-xl bg-gray-200 p-6 text-gray-800 dark:bg-gray-700 dark:text-gray-200"
>
<form
method="POST"
wire:submit.prevent="submitNewForm"
action="{{ route("subreddits.store") }}"
class="inline-flex w-full justify-between gap-2"
>
@csrf
<label>
<input
wire:model.defer="name"
type="text"
class="w-full rounded-xl bg-gray-100 p-2 dark:bg-gray-800 dark:text-gray-200"
placeholder="Subreddit"
name="name"
/>
</label>
<button
class="text-nowrap rounded-xl bg-gray-100 p-2 text-sm hover:bg-blue-400 dark:bg-blue-600 dark:text-gray-200"
>
Add Subreddit
</button>
</form>
@if (session()->has("new_error"))
<span class="rounded-xl pl-2 text-sm text-red-600">
{{ session("new_error") }}
</span>
@endif
@if (session()->has("new_success"))
<span class="rounded-xl pl-2 text-sm text-green-600">
{{ session("new_success") }}
</span>
@endif
<div class="mt-4 h-fit min-h-64 w-full rounded-xl bg-gray-600 p-1">
<ol class="flex flex-col gap-2">
@foreach ($profile->subreddits()->get() as $subreddit)
<li
wire:key="subreddit-{{ $subreddit->id }}"
class="relative rounded-xl bg-gray-100 p-2 hover:bg-blue-600 dark:bg-gray-800 dark:text-gray-200"
>
<button
wire:click="$dispatch('openSubredditModal', [{{ $subreddit->id }}])"
wire:key="subreddit-{{ $subreddit->id }}"
class="w-full h-full">
r/{{ $subreddit->name }}
</button>
<livewire:subreddit-modal :subreddit="$subreddit" :profile="$profile" :key="'subreddit-modal-' . $subreddit->id" />
</li>
@endforeach
</ol>
</div>
</div>
subreddit-modal
<div>
<form
wire:submit.prevent="updateSubreddit"
class="{{ $isOpen ? 'flex' : 'hidden' }} flex justify-center left-0 top-0 fixed w-full h-full bg-black bg-opacity-50 z-50">
<div
class="mt-4 space-y-5 h-fit min-h-64 w-full max-w-2xl rounded-xl bg-gray-200 p-6 text-gray-800 dark:bg-gray-700 dark:text-gray-200">
<div
class="inline-flex gap-4 text-center font-bold text-2xl bg-gray-100 p-2 dark:bg-gray-800 dark:text-gray-200 rounded-xl w-full">
<h1 class="w-full">
Edit r/{{ $subreddit->name }}
</h1>
<button
wire:loading.attr="disabled"
type="button"
wire:click="closeModal"
class="rounded-full bg-gray-100 w-8 h-8 text-sm hover:bg-red-400 dark:bg-gray-700 dark:text-gray-200">
X
</button>
</div>
<div>
<label class="flex flex-col text-xl italic text-gray-400">
Subreddit Name
<span class="text-xs">
This is where your advert will be posted, please make sure it is correct.
</span>
<input type="text" wire:model.live.debounce="name"
class="mt-2 w-full rounded-xl bg-gray-100 p-2 dark:bg-gray-800 dark:text-gray-200"
placeholder="Subreddit" name="name">
</label>
{{-- @error('name')--}}
<label class="flex flex-col text-xl italic text-gray-400">
Flair
<span class="text-xs">
This is the flair that will be attached to your post.
</span>
@isset($subreddit->available_flairs)
<select
wire:model="flair"
class="mt-2 w-full rounded-xl bg-gray-100 p-2 dark:bg-gray-800 dark:text-gray-200"
>
<option value="None">None</option>
@forelse(json_decode($subreddit->available_flairs, true, 512, JSON_THROW_ON_ERROR) as $flair)
<option
value="{{ $flair['id'] }}"
{{ $subreddit->flair === $flair['id'] ? "selected" : "" }}
>
{!! clean($flair['text']) !!}
</option>
@empty
@endforelse
</select>
@else
<p class="text-red-500 text-xs text-center w-full">
No flairs found
</p>
@endisset
</label>
<label class="flex flex-col text-xl italic text-gray-400">
Maximum title length
<span class="text-xs">
This is the maximum length of the title of your post. Some subreddits may have a limit on the length of the title, you can use this to comply to those limits.
</span>
<input type="number" wire:model.live.debounce="titlelimit"
max=300
min=1
class="mt-2 w-full rounded-xl bg-gray-100 p-2 dark:bg-gray-800 dark:text-gray-200"
placeholder="Title Length" name="titlelimit" id="titlelimit">
</label>
<label class="flex flex-col text-xl italic text-gray-400">
Title Prefix
<span class="text-xs">
This is the prefix that will be added to the beginning of the title.
</span>
<input type="text" wire:model.live.debounce="prefix"
class="mt-2 w-full rounded-xl bg-gray-100 p-2 dark:bg-gray-800 dark:text-gray-200"
placeholder="Title Prefix" name="prefix" id="prefix">
</label>
<div class="flex flex-row justify-between mt-2">
<button
type="submit"
@click="open = !open"
class="p-2 px-6 font-bold hover:bg-blue-500 text-blue-500 hover:text-gray-200 rounded-xl border border-blue-600"
>
Update
</button>
<button
wire:click="deleteSubreddit('{{ $subreddit->name }}'); open = !open"
type="button"
class="p-2 px-6 font-bold hover:bg-red-500 text-red-500 hover:text-gray-200 rounded-xl border border-red-600"
>
Delete
</button>
</div>
</div>
</div>
</form>
</div>
subredditBar.php
<?php
namespace AppLivewire;
use AppModelsSubreddits;
use AppSupportReddit;
use LivewireComponent;
class SubredditBar extends Component
{
public $profile;
public $profile_id;
public $name;
public $subreddit;
// protected $listeners= ['$refresh'];
protected $rules = [
'name' => 'required',
'profile_id' => 'required'
];
public function getListeners(): array
{
return [
'refreshSubredditBar' => '$refresh',
];
}
public function mount($profile): void
{
$this->profile = $profile;
$this->profile_id = $profile->id;
}
public function editSubreddit(): void
{
}
public function changeFlair($sr): void
{
$new = $this->validate(['name' => 'required']);
$sub = Subreddits::where('name', $sr)->where('profile_id', $this->profile_id);
$sub->update($new);
session()->flash('new_success', 'flair changed successfully');
}
public function RenameSubreddit($sr): void
{
$new = $this->validate(['name' => 'required']);
$sub = Subreddits::where('name', $sr)->where('profile_id', $this->profile_id);
$sub->update($new);
session()->flash('new_success', 'subreddit renamed successfully');
}
public function submitNewForm(): void
{
$existingSubreddit = Subreddits::where('name', $this->name)
->where('profile_id', $this->profile_id)
->first();
if ($existingSubreddit) {
session()->flash('new_error', 'Subreddit already exists');
return;
}
if (!$this->profile->access_token) {
session()->flash('new_error', 'Please connect your reddit account first');
return;
}
$flairs = Reddit::getSubredditsFlairs($this->profile, $this->name);
try {
$attr = $this->validate();
session()->flash('new_error', count($flairs));
// if(count($flairs) < 1){
// session()->flash('new_error', 'Please connect your reddit account first');
// return;
// }
$sr = Subreddits::create($attr);
$sr->update(['available_flairs' => json_encode($flairs, true)]);
} catch (Exception $e) {
session()->flash('new_error', 'Something went wrong: ' . $e->getMessage());
}
session()->flash('new_success', 'Subreddit created successfully');
$this->name = '';
}
public function render()
{
return view('livewire.subreddit-bar');
}
}
subredditModal.php
<?php
namespace AppLivewire;
use AppModelsSubreddits;
use AppSupportReddit;
use LivewireComponent;
class SubredditModal extends Component
{
public $isOpen;
public $subreddit;
public $profile;
public $name;
public $flair;
public $titlelimit;
public $prefix;
public $rules = [
'name' => 'required',
'flair' => 'nullable',
'titlelimit' => 'nullable',
'prefix' => 'nullable'
];
protected $listeners = ['openSubredditModal' => 'openModal'];
public function openModal($id): void
{
if ($this->subreddit->id === $id) {
$this->isOpen = true;
}
}
public function closeModal(): void
{
$this->isOpen = false;
}
public function mount()
{
$this->name = $this->subreddit->name;
$this->flair = $this->subreddit->flair;
$this->titlelimit = $this->subreddit->titlelimit;
$this->prefix = $this->subreddit->prefix;
$this->isOpen = false;
}
public function updateSubreddit(): void
{
if (!$this->profile->access_token) {
session()->flash('new_error', 'Please connect your reddit account first');
return;
}
$flairs = Reddit::getSubredditsFlairs($this->profile, $this->name);
$new = $this->validate();
$new['available_flairs'] = json_encode($flairs, true);
if ($new['flair'] === "None") {
unset($new['flair']);
}
$this->subreddit->update($new);
$this->dispatch('refreshSubredditBar');
$this->closeModal();
session()->flash('new_success', 'subreddit updated successfully');
}
public function deleteSubreddit(): void
{
$this->subreddit->delete();
$this->dispatch('refreshSubredditBar');
$this->closeModal();
session()->flash('new_success', 'subreddit deleted successfully');
}
public function render()
{
return view('livewire.subreddit-modal');
}
}