F
Filament16mo ago
Darpan

How to prevent already selected value in repeater?

I am using repeater to add working hours and I don't want users to select same day twice. How can I prevent this?
12 Replies
toeknee
toeknee16mo ago
Are you using a select in the repeater? The only way I can think of is to get the variables in the repeater and query them on a custom rule
Darpan
Darpan16mo ago
Yes, I am using select in the repeater. Can you please show how?
toeknee
toeknee16mo ago
IIRC you can call the repeater name to get the array of elements with a closure in rules and pass it in to validate itv
Garadit
Garadit12mo ago
Has the problem been resolved? I'm a bit lost on how to do that for Select Columns
toeknee
toeknee12mo ago
So you would have to go through all the fields with a closure and check their values to ensure it’s not been selected.
Garadit
Garadit12mo ago
I just want it to work like multiselect, which doesn't show the selection when it's already selected in another repeater. If using rules, won't it check it after the form is submitted (clicked submit)?
awcodes
awcodes12mo ago
Validation is your best bet here. Think about it. A repeater uses the same fields when a new item is added, so if you remove an option from the select then it will no longer exist as an option in the places it’s already been set nulling those out.
Garadit
Garadit12mo ago
Make sense now
Darpan
Darpan12mo ago
I am doing this like below, this may not be perfect solution but its working for me. Repeater:
TableRepeater::make('working_hours')->schema([
Select::make('day')
->disableLabel()
->required()
->rule('required')
->options(
fn($state, $get) => VcardFormHelper::getDays($state, $get)
),

// other fields
])
->createItemButtonLabel('Add working hours')
->defaultItems(0)
->maxItems(7)
->disableLabel(),
TableRepeater::make('working_hours')->schema([
Select::make('day')
->disableLabel()
->required()
->rule('required')
->options(
fn($state, $get) => VcardFormHelper::getDays($state, $get)
),

// other fields
])
->createItemButtonLabel('Add working hours')
->defaultItems(0)
->maxItems(7)
->disableLabel(),
Get days:
public static function getDays(string|null $state, Closure $get): array
{
// All days
$days = [
'monday' => 'Monday',
'tuesday' => 'Tuesday',
'wednesday' => 'Wednesday',
'thursday' => 'Thursday',
'friday' => 'Friday',
'saturday' => 'Saturday',
'sunday' => 'Sunday',
];

// Get all repeater items
$workingHours = $get('../../working_hours');

// Retrieve days from repeater items
$existing = array_column($workingHours, 'day');

// Remove null days
$existing = array_filter($existing);

// Remove all existing options from days
$options = array_diff_key($days, array_flip($existing));

// Check if current option is not null
if ($state !== null) {
// Add current state to items and return
return array_merge($options, [$state => $days[$state]]);
}

return $options;
}
public static function getDays(string|null $state, Closure $get): array
{
// All days
$days = [
'monday' => 'Monday',
'tuesday' => 'Tuesday',
'wednesday' => 'Wednesday',
'thursday' => 'Thursday',
'friday' => 'Friday',
'saturday' => 'Saturday',
'sunday' => 'Sunday',
];

// Get all repeater items
$workingHours = $get('../../working_hours');

// Retrieve days from repeater items
$existing = array_column($workingHours, 'day');

// Remove null days
$existing = array_filter($existing);

// Remove all existing options from days
$options = array_diff_key($days, array_flip($existing));

// Check if current option is not null
if ($state !== null) {
// Add current state to items and return
return array_merge($options, [$state => $days[$state]]);
}

return $options;
}
toeknee
toeknee12mo ago
Good work
Garadit
Garadit12mo ago
This is working very well, thank you
DianaMujoiu
DianaMujoiu5mo ago
Hello, regarding this implementation, does the first select retain its selection when you add a new item? Because when I add a new item, the first selection disappears