F
Filament13mo ago
ejoi8

How to "$set" Repeater itemLabel()

Select::make('quantity')
->options([
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
])
->afterStateUpdated(function (Get $get, Set $set) {

$name = array_fill(0, $get('quantity'), [
'name' => '',
]);

$set('members', $name);
})
->live(),

Repeater::make('members')
->schema([
TextInput::make('name')->required()->label('Name'),
])
->itemLabel("Student")
->hidden(fn (Get $get): bool => !$get('quantity'))
->addable(false)
->columns(1)
->collapsible()
->deletable(false)
->reorderable(false)
->live(),
Select::make('quantity')
->options([
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
])
->afterStateUpdated(function (Get $get, Set $set) {

$name = array_fill(0, $get('quantity'), [
'name' => '',
]);

$set('members', $name);
})
->live(),

Repeater::make('members')
->schema([
TextInput::make('name')->required()->label('Name'),
])
->itemLabel("Student")
->hidden(fn (Get $get): bool => !$get('quantity'))
->addable(false)
->columns(1)
->collapsible()
->deletable(false)
->reorderable(false)
->live(),
Hi... I manage to set repeater number base on the Select::make('quantity') but how can I set itemLabel in afterStateUpdated? Let say if the selected quantity is 3, the repeater will generate 3 Repeater TextInput with itemlabel value "Student" to all 3. How can I dynamically make it "Student 1", "Student 2", "Student 3"
No description
Solution:
```php Select::make('quantity') ->options([ '1' => 1, '2' => 2,...
Jump to solution
8 Replies
awcodes
awcodes13mo ago
ItemLabel should accept a callback where you can return whatever you need as the label.
ejoi8
ejoi8OP13mo ago
If use callback in ItemLabel, the return value still will be same to all the generated Repeater. I just want to append numbering ,maybe by using some sort of array index value but I have no idea where to start
awcodes
awcodes13mo ago
Not a copy paste solution but explore this.
$repeater = $component->getParentRepeater();

if (! $repeater) {
return;
}

$repeaterStatePath = $repeater->getStatePath();

$componentItemStatePath = (string) str($component->getStatePath())
->after("{$repeaterStatePath}.")
->after('.');

$repeaterItemKey = (string) str($component->getStatePath())
->after("{$repeaterStatePath}.")
->beforeLast(".{$componentItemStatePath}");
$repeater = $component->getParentRepeater();

if (! $repeater) {
return;
}

$repeaterStatePath = $repeater->getStatePath();

$componentItemStatePath = (string) str($component->getStatePath())
->after("{$repeaterStatePath}.")
->after('.');

$repeaterItemKey = (string) str($component->getStatePath())
->after("{$repeaterStatePath}.")
->beforeLast(".{$componentItemStatePath}");
Basically, you just need a way to check the value in the repeater array to return the key of the state. Sudo code: Foreach(state as key => value) If value === blah return ‘Student ’ . Key I’m sure I’m not explaining it well, but the itemLabel has access to the state which for a repeater will be an array so you can use any php conventions to determine the index of the array that works for your use case.
ejoi8
ejoi8OP12mo ago
alright, I will take a look into it... thanks @awcodes
Solution
ejoi8
ejoi812mo ago
Select::make('quantity')
->options([
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
])
->afterStateUpdated(function (Get $get, Set $set) {

$name = array_fill(0, $get('quantity'), [
'name' => '',
]);

$set('members', $name);
})
->live(),

Repeater::make('members')
->schema([
TextInput::make('name')->required()->label('Name'),
])
->itemLabel(function (Get $get) {
foreach ($get('members') as $key => $value) {
Log::info($get('members'));
return $key;
}
})
->hidden(fn (Get $get): bool => !$get('quantity'))
->addable(false)
->columns(1)
->collapsible()
->deletable(false)
->reorderable(false)
->live(),
Select::make('quantity')
->options([
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
])
->afterStateUpdated(function (Get $get, Set $set) {

$name = array_fill(0, $get('quantity'), [
'name' => '',
]);

$set('members', $name);
})
->live(),

Repeater::make('members')
->schema([
TextInput::make('name')->required()->label('Name'),
])
->itemLabel(function (Get $get) {
foreach ($get('members') as $key => $value) {
Log::info($get('members'));
return $key;
}
})
->hidden(fn (Get $get): bool => !$get('quantity'))
->addable(false)
->columns(1)
->collapsible()
->deletable(false)
->reorderable(false)
->live(),
I did this but the foreach inside itemLabel will repeat entire array. Let say I select the quantity 2, then the loop log (Log::info($get('members'))) will look something like this
[2023-11-25 02:08:49] local.INFO: array (
0 =>
array (
'name' => '',
),
1 =>
array (
'name' => '',
),
)
[2023-11-25 02:08:49] local.INFO: array (
0 =>
array (
'name' => '',
),
1 =>
array (
'name' => '',
),
)
[2023-11-25 02:08:49] local.INFO: array (
0 =>
array (
'name' => '',
),
1 =>
array (
'name' => '',
),
)
[2023-11-25 02:08:49] local.INFO: array (
0 =>
array (
'name' => '',
),
1 =>
array (
'name' => '',
),
)
Lastly, what I did is I add another id array in afterStateUpdated and add another TextInput::make('id')->hidden() in the repeater schema then add ->itemLabel(fn (array $state): ?string => 'Student '.$state['id'] ?? null). Seem like confusing but here is the full code
ejoi8
ejoi8OP12mo ago
Select::make('quantity')
->options([
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
])
->afterStateUpdated(function (Get $get, Set $set) {

$name = array_map(function ($index) {
return [
'id' => $index,
'name' => '',
];
}, range(1, $get('quantity')));

$set('members', $name);

})
->live(),

Repeater::make('members')
->schema([
TextInput::make('id')->hidden(),
TextInput::make('name')->required()->label('Name'),
])
->itemLabel(fn (array $state): ?string => 'Student '.$state['id'] ?? null)
->hidden(fn (Get $get): bool => !$get('quantity'))
->addable(false)
->columns(1)
->collapsible()
->deletable(false)
->reorderable(false)
->live(),
Select::make('quantity')
->options([
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
])
->afterStateUpdated(function (Get $get, Set $set) {

$name = array_map(function ($index) {
return [
'id' => $index,
'name' => '',
];
}, range(1, $get('quantity')));

$set('members', $name);

})
->live(),

Repeater::make('members')
->schema([
TextInput::make('id')->hidden(),
TextInput::make('name')->required()->label('Name'),
])
->itemLabel(fn (array $state): ?string => 'Student '.$state['id'] ?? null)
->hidden(fn (Get $get): bool => !$get('quantity'))
->addable(false)
->columns(1)
->collapsible()
->deletable(false)
->reorderable(false)
->live(),
ejoi8
ejoi8OP12mo ago
and here is the output
No description
ejoi8
ejoi8OP12mo ago
The idea is I want add numbering to each repeater. The list could be large so the numbering will help user to identify how many list are there I believe there could be better workaround on this and please share here if you do so.
Want results from more Discord servers?
Add your server