Livewire Component in Custom Field Shares State within a Repeater

Just for context: I am using a simplified scenario here as I can not share the actual code. What I am trying to do: I am trying to use a Livewire component that is rendered via a custom Filament Field inside a Repeater. Each instance of the Livewire component should manage its own state independently. For context, I am relatively new to the TALL stack. What I did: 1. I set up a Filament Repeater to allow adding multiple blocks. 2. Inside the repeater's schema, I have a custom Filament Field class called DataGrid. 3. The DataGrid field's view renders a Livewire component, DataGridComponent. 4. The Livewire component's state is bound to the Filament field's state via wire:model. My issue/the error: When I add a second item to the Repeater, the new instance of the DataGridComponent shares its state with the first instance. Modifying the data in one component (e.g., adding a row) concurrently modifies the data in the other. The root cause appears to be that a non-unique :key is being passed to the Livewire components. My current implementation uses :key="$this->getID()" within the custom field's view, but $this->getID() returns an identical value for every item in the repeater. My Question: What is the correct method to supply a unique key to a Livewire component that is rendered by a custom field's view for each item within a Filament Repeater?
1 Reply
Ferdmusic
FerdmusicOP2mo ago
Code
// Inside a resource form
Repeater::make('pageBlocks')
->schema([
// ... other fields
\App\Forms\Components\DataGrid::make('table_data')
->live()
->statePath('data'),
]);
// Inside a resource form
Repeater::make('pageBlocks')
->schema([
// ... other fields
\App\Forms\Components\DataGrid::make('table_data')
->live()
->statePath('data'),
]);
// app/Forms/Components/DataGrid.php
namespace App\Forms\Components;

use Filament\Forms\Components\Field;

class DataGrid extends Field
{
protected string $view = 'forms.components.data-grid';
}
// app/Forms/Components/DataGrid.php
namespace App\Forms\Components;

use Filament\Forms\Components\Field;

class DataGrid extends Field
{
protected string $view = 'forms.components.data-grid';
}
// resources/views/forms/components/data-grid.blade.php
<x-dynamic-component :component="$getFieldWrapperView()" :field="$field">
<div>
{{-- This value is identical for each repeater item --}}
<input type="hidden" value="{{ $this->getId() }}">

<livewire:data-grid-component
wire:model="{{ $getStatePath() }}"
:key="$this->getID()" />
</div>
</x-dynamic-component>
// resources/views/forms/components/data-grid.blade.php
<x-dynamic-component :component="$getFieldWrapperView()" :field="$field">
<div>
{{-- This value is identical for each repeater item --}}
<input type="hidden" value="{{ $this->getId() }}">

<livewire:data-grid-component
wire:model="{{ $getStatePath() }}"
:key="$this->getID()" />
</div>
</x-dynamic-component>
// app/Livewire/DataGridComponent.php
namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Modelable;

class DataGridComponent extends Component
{
#[Modelable]
public ?array $data = [];

public function mount(): void
{
$this->data['rows'] ??= [];
$this->data['columns'] ??= [];
}

public function addRow(): void
{
$this->data['rows'][] = ['id' => uniqid()];
}

public function render()
{
return view('livewire.data-grid-component');
}
}
// app/Livewire/DataGridComponent.php
namespace App\Livewire;

use Livewire\Component;
use Livewire\Attributes\Modelable;

class DataGridComponent extends Component
{
#[Modelable]
public ?array $data = [];

public function mount(): void
{
$this->data['rows'] ??= [];
$this->data['columns'] ??= [];
}

public function addRow(): void
{
$this->data['rows'][] = ['id' => uniqid()];
}

public function render()
{
return view('livewire.data-grid-component');
}
}
Nevermind, I found the issue🤦‍♀️ The solution was to use ':key="$getId()"' - two days of my life wasted haha

Did you find this page helpful?