I'm a beginner with Livewire3 trying to figure it all out. Unfortunately, I've encountered a problem I can't solve.
I built one large component containing a list of "products," which includes components for sorting and filtering the list by category. This component loops around a blade component with a product card. This blade component loads two Livewire components: one for sending product information by email and one for adding to favorites. Of course, the product list is paginated.
The sorting and category filtering components, via $wire.$parent, call the methods of the product list component. The components for sending emails and adding to favorites operate on their own and call their own methods, as they don't interact with the product list itself. And at this point, I'm just lost. After the page loads, everything works, of course. Changing pages also works. And the components on the product card work. Unfortunately, as soon as I use the sorting or filtering components, some of the components for sending emails or adding to favorites disappear from the page, and Livewire throws up component-not-found errors. I've marked everything I could with wire:key, including the product list itself. The sorting components have a static ID because their content doesn't change at all. The product card, although a blade component and not a Livewire component, also has an ID associated with the product ID. Below is the problematic code. I omitted the components for sending emails and setting favorites, as the problems persist regardless of whether I use them. Thanks in advance for your help.
Main HTML:
@extends('layouts.shop')
@section('title', 'Items list')
@section('content')
<div class="page-heading">
<h1>@yield('title')</h1>
</div>
<livewire:items.items-list />
@endsection
items/items-list.blade.php:
<div wire:key="items-list" class="items-list-container">
<livewire:widgets.sort-dropdown :sortOptions="$this->sortOptions" :sort="$this->sort" :context="$this->context" />
<livewire:widgets.category-dropdown :categories="$this->categories" :selected="$this->selectedCategories" />
{{ $items->links('pagination-test') }}
@foreach($items as $item)
<x-items.item-card :item="$item"/>
@endforeach
</div>
category dropdown widget (sort looks pretty much the same):
<div class="dropdown-menu category-menu" x-data="{
open: false,
text: '{{ $this->text }}',
selected: @entangle('selected') || [],
categories: @entangle('categories') || [],
selectedAll: false,
updateState() {
/* update text of dropdown button */
},
update() {
this.updateState();
$wire.$parent.setCategories(this.selected);
},
all() {
this.selected = [];
this.update();
}}" x-ref="dropdown" x-init="updateState()" wire:key="category-dropdown">
<a @click.prevent="open = !open" x-text="text">
{{ $this->text }}
</a>
<ul x-show="open">
<li>
<input name="select_all" type="checkbox" x-model="selectedAll" class="checkbox checkbox-xs" @click="if(selectedAll) $event.preventDefault(); else all();" /> show all
</li>
@foreach($this->categories as $category)
<li>
<input name="category[]" type="checkbox" x-model="selected" value="{{$category->id}}" @change="update()" class="checkbox checkbox-xs" />
{{ $category->name }}
</li>
@endforeach
</ul>
</div>
Item card:
<div wire:key="item-{{ $item->id }}">
<x-items.item-metadata :item="$item" />
<!-- these are those two components that are lost after setSort or setCategories -->
<livewire:items.mail-button wire:key="mail-{{ $item->id }}" />
<livewire:widgets.bookmark-toggle :item="$item" wire:key="bookmark-{{ $item->id }}" />
</div>
ItemsList component:
<?php
namespace App\Livewire\Items;
use Closure;
use Illuminate\Contracts\View\View;
use Livewire\Component;
use Livewire\WithPagination;
class ItemsList extends Component
{
use WithPagination;
public ?string $sort = null;
private array $sortOptions = [];
public array $selectedCategories = [];
public function setCategories(array $selectedCategories): void
{
$this->selectedCategories = $selectedCategories;
$this->resetPage();
}
public function setSort(string $sort): void
{
$this->sort = $sort;
$this->resetPage();
}
public function mount(): void {}
public function render(): View|Closure|string
{
$items = app(ItemService::class)->listPaginated(categories: $this->selectedCategories, sort: $this->sort);
return view('livewire.items.items-list', compact('items'));
}
public function queryString(): array
{
$queryString = [
'sort' => ['except' => '', 'keep' => false, 'history' => true],
'filterCategories' => ['except' => '', 'keep' => false, 'history' => true]
];
return $queryString;
}
public function updatedPage(): void
{
$this->dispatch('scroll-to-top');
}
}