How customize Repeater's item using Livewire component?

Livewire 3x. I have a Livewire component OpportunityQuote that has a Repeater in its structure, like this:
class OpportunityQuote extends Component implements HasForms
{
use InteractsWithForms, CanGenerateUuids;

public $quote_services = [];

public function mount()
{
$this->quote_services = [];
$this->form->fill([
'quote_services_repeater' => $this->quote_services,
]);
}

public function form(Form $form): Form
{
return $form
->schema([
Repeater::make('quote_services_repeater')
->label('Serviços Adicionados')
->itemLabel(function (array $state) {
return new HtmlString(
view('filament.components.service-repeater-item')
->with('state', $state)->render()
);
})
->schema(function (array $state) {
return [
// Livewire::make(OpportunityQuoteItem::class, [
// 'item' => $state
// ]),
TextInput::make('name')
->email()->label('Email'),
];
})
->columns(4)
->defaultItems(1)
->collapsible()
->collapsed()
->orderable(false)
->addable(false)
])->statePath('quote_services');
}

public function onAddedService($item, $index)
{
$uuid = $this->generateUuid();
$this->quote_services['quote_services_repeater'][$uuid] = $item;
$this->form->fill([
'quote_services_repeater' => $this->quote_services['quote_services_repeater'],
]);
}
class OpportunityQuote extends Component implements HasForms
{
use InteractsWithForms, CanGenerateUuids;

public $quote_services = [];

public function mount()
{
$this->quote_services = [];
$this->form->fill([
'quote_services_repeater' => $this->quote_services,
]);
}

public function form(Form $form): Form
{
return $form
->schema([
Repeater::make('quote_services_repeater')
->label('Serviços Adicionados')
->itemLabel(function (array $state) {
return new HtmlString(
view('filament.components.service-repeater-item')
->with('state', $state)->render()
);
})
->schema(function (array $state) {
return [
// Livewire::make(OpportunityQuoteItem::class, [
// 'item' => $state
// ]),
TextInput::make('name')
->email()->label('Email'),
];
})
->columns(4)
->defaultItems(1)
->collapsible()
->collapsed()
->orderable(false)
->addable(false)
])->statePath('quote_services');
}

public function onAddedService($item, $index)
{
$uuid = $this->generateUuid();
$this->quote_services['quote_services_repeater'][$uuid] = $item;
$this->form->fill([
'quote_services_repeater' => $this->quote_services['quote_services_repeater'],
]);
}
4 Replies
zesimples
zesimplesOP2mo ago
For each item in my Repeater, I will have another custom Livewire component.
class OpportunityQuoteItem extends Component
{
public ?array $item = [];

public function mount($item)
{
$this->item = $item;
}

public function render()
{
return view('livewire.opportunity.quote-item');
}
}
class OpportunityQuoteItem extends Component
{
public ?array $item = [];

public function mount($item)
{
$this->item = $item;
}

public function render()
{
return view('livewire.opportunity.quote-item');
}
}
How do I make each line of my Repeater with custom component to have the current item? If we look at the itemLabel method, it has by default a $state that represents the current line, so you can customize the title. But, Within the schema method, the variable $state does not just represent a line, but rather the state of the Repeater as a whole, being multi-dimensional array. But, how do I do this?
hyperion-mx
hyperion-mx2mo ago
You have access to both $arguments as array and $component as Repeater, using the $component you can get the current item state as a casted array, here is an example from the docs
Repeater::make('members')
->schema([
TextInput::make('email')
->label('Email address')
->email(),
// ...
])
->extraItemActions([
Action::make('sendEmail')
->icon('heroicon-m-envelope')
->action(function (array $arguments, Repeater $component): void {
$itemData = $component->getItemState($arguments['item']);

Mail::to($itemData['email'])
->send(
// ...
);
}),
])
Repeater::make('members')
->schema([
TextInput::make('email')
->label('Email address')
->email(),
// ...
])
->extraItemActions([
Action::make('sendEmail')
->icon('heroicon-m-envelope')
->action(function (array $arguments, Repeater $component): void {
$itemData = $component->getItemState($arguments['item']);

Mail::to($itemData['email'])
->send(
// ...
);
}),
])
Applying it to your case
zesimples
zesimplesOP2mo ago
In my case, I dont have extra actions ... I was needing to get this $arguments['item'] inside schema method, but, it is not possible
LeandroFerreira
LeandroFerreira2mo ago
I think in the repeater you could use a ViewField
Repeater::make('quote_services_repeater')
->schema([
...
ViewField::make('customView')
->view('custom-view')
])
Repeater::make('quote_services_repeater')
->schema([
...
ViewField::make('customView')
->view('custom-view')
])
Render the LW component in the view and pass the component state that you need
<!-- custom-view.blade.php -->
<div>
@livewire(OpportunityQuoteItem::class, [
'name' => $getGetCallback()('name')
], key('xxx'))
</div>
<!-- custom-view.blade.php -->
<div>
@livewire(OpportunityQuoteItem::class, [
'name' => $getGetCallback()('name')
], key('xxx'))
</div>
class OpportunityQuoteItem extends Component
{
public ?string $name = null;
class OpportunityQuoteItem extends Component
{
public ?string $name = null;
Want results from more Discord servers?
Add your server