Issues with dynamic checkboxlist state in multi-step wizard form

Hi everyone, I am trying to update a CheckboxList depending on the value of a field set in a previous step of a Wizard form. The following code works fine and displays the CheckboxList as expected. However, it seems that all the CheckboxList boxes have the same state, so when I check one box, all the boxes are checked. This seems to be related to how I pass the $get('user_id') value from one step to another. If I hardcode the numeric id instead of the variable, everything works as expected. If I add a debug at the beginning of the second step, I see that the query() is called multiple times, including when the document_id is not set up yet, which is not really what I would expect either. I am really confused as to how to approach the problem. What would you do? EDIT: my message is too long to paste the code, so I shared it in the first reply.
Solution:
You could load them all in, then hide them with the getter
Jump to solution
16 Replies
Grégoire
Grégoire2mo ago
Here is the code:
public ?array $data = [];

public function mount(): void
{
$this->form->fill();
}

public function form(Form $form): Form
{
return $form
->schema([
Wizard::make([
Wizard\Step::make('Settings')
->schema([
Select::make('user_id')
->options(function (Get $get): array {
return User::query()
->get()
->pluck('name', 'id')
->toArray();
})
->native(false)
->live()
->required(),
]),
Wizard\Step::make('Documents')
->schema(function (Get $get) {
return Document::query()
->where('user_id', $get('user_id'))
->get()
->groupBy('type')
->map(function ($documents) {
return CheckboxList::make($documents->first()->type->value)
->label(false)
->options($documents->pluck('title', 'id')
->toArray())
->bulkToggleable()
->searchable()
->columns(2);
})->toArray();
}),
]),
])->statePath('data');
}
public ?array $data = [];

public function mount(): void
{
$this->form->fill();
}

public function form(Form $form): Form
{
return $form
->schema([
Wizard::make([
Wizard\Step::make('Settings')
->schema([
Select::make('user_id')
->options(function (Get $get): array {
return User::query()
->get()
->pluck('name', 'id')
->toArray();
})
->native(false)
->live()
->required(),
]),
Wizard\Step::make('Documents')
->schema(function (Get $get) {
return Document::query()
->where('user_id', $get('user_id'))
->get()
->groupBy('type')
->map(function ($documents) {
return CheckboxList::make($documents->first()->type->value)
->label(false)
->options($documents->pluck('title', 'id')
->toArray())
->bulkToggleable()
->searchable()
->columns(2);
})->toArray();
}),
]),
])->statePath('data');
}
toeknee
toeknee2mo ago
You need to define a name for the make function. It needs to be unique
Grégoire
Grégoire2mo ago
Thanks toeknee, it's my fault, I simplified my code a bit before posting and the make function is indeed unique. I have updated the code. Actually each checkbox list is independent, its the boxes within it that share the same state.
toeknee
toeknee2mo ago
Looks like it should work, inspect the checkbox list and ensure they all have unique option values.
Grégoire
Grégoire2mo ago
Thank you for your answer! Actually, I am pretty sure that my values are good. I think the problem is more likely that the documents are empty at first and then generated a second time. The following example generates visually exactly the same thing, but in the first case it works as expected and in the second case all states of a single CheckboxList are linked.
// This is working:
->schema(function (Get $get) {
$documents = Document::query()
->where('user_id', $get('user_id'))
->get()
->groupBy('user_id');

for ($i = 0; $i < 10; $i++) {
$fieldsets[] = CheckboxList::make('documents-' . $i)
->options([
'tailwind' => 'Tailwind CSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
]);
}
return $fieldsets;
});

// This is not working:
->schema(function (Get $get) {
$documents = Document::query()
->where('user_id', $get('user_id'))
->get()
->groupBy('user_id');

$i = 0;
foreach ($documents as $document) {
$fieldsets[] = CheckboxList::make('documents-' . $i)
->options([
'tailwind' => 'Tailwind CSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
]);
$i++;
}
return $fieldsets ?? [];
});
// This is working:
->schema(function (Get $get) {
$documents = Document::query()
->where('user_id', $get('user_id'))
->get()
->groupBy('user_id');

for ($i = 0; $i < 10; $i++) {
$fieldsets[] = CheckboxList::make('documents-' . $i)
->options([
'tailwind' => 'Tailwind CSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
]);
}
return $fieldsets;
});

// This is not working:
->schema(function (Get $get) {
$documents = Document::query()
->where('user_id', $get('user_id'))
->get()
->groupBy('user_id');

$i = 0;
foreach ($documents as $document) {
$fieldsets[] = CheckboxList::make('documents-' . $i)
->options([
'tailwind' => 'Tailwind CSS',
'alpine' => 'Alpine.js',
'laravel' => 'Laravel',
'livewire' => 'Laravel Livewire',
]);
$i++;
}
return $fieldsets ?? [];
});
Grégoire
Grégoire2mo ago
Hi again 👋 I've tried just about everything I can think of, and I'd just like to check with you whether this is a skill issue (which it probably is), or a proper, non-expected behaviour of filament. I have created a minimal repository after seeding the database (email: test@filamentphp.com ; password: password), which you can find here: https://github.com/CeriseGoutPelican/filament-issue
toeknee
toeknee2mo ago
I am not seeing any select / checkbox in this repo found it
Grégoire
Grégoire2mo ago
Oh, I put it in Settings in the admin panel. Maybe that was not the most logical place to put it. If I can help you investigate in any way, please do not hesitate. In the meantime, I've found a workaround for the project by creating all possible checkbox lists, dynamically hiding the ones I don't need, and updating the chexboxes instead. It is not great because it is heavy and calls the database once for each category (instead of just once).
toeknee
toeknee2mo ago
It's because you are using the getter it's causing an issue Likely because the elements are not loaded in on mount if you for example remove the ->where('user_id', $get('user_id')) then the issue disappears...
Grégoire
Grégoire2mo ago
Yes, it is definitely the getter, I have identified that earlier, but I will still need it. However, what you said about all elements needing to be initiated first is exactly what I missed in my investigation.
toeknee
toeknee2mo ago
How many categories do you forsee there being?
Solution
toeknee
toeknee2mo ago
You could load them all in, then hide them with the getter
Grégoire
Grégoire2mo ago
Not that many, in the project I have up to 14, all stored in an enum. That's exactly what I will do, loop through the enum, generate empty checkboxlists and then update them when needed.
toeknee
toeknee2mo ago
Perfect
Grégoire
Grégoire2mo ago
Thank you for taking the time to investigate, I have sent you a small donation 🙂
Want results from more Discord servers?
Add your server