Absolutely, this is a common scenario when dealing with "virtual" fields in FilamentPHP forms. The core issue is that afterStateHydrated runs every time the form is hydrated (including after submit/validation), so it can override user input if not carefully conditioned. Meanwhile, default() only applies on creation, not on edit.
Here’s a robust approach that solves all your requirements:
- Show the checkbox as checked if
guarantor_idexists. - Respect the user’s changes (don’t re-check it automatically).
- Clear
guarantor_idif user unchecks it. - Keep logic inside the Filament field definition.
Solution
The trick is to only set the checkbox state in afterStateHydrated if the user hasn’t already interacted with the field. Filament provides a way to check if the state is already set (i.e., the user has interacted or the form has been submitted).
Here’s the recommended setup:
Checkbox::make('add_guarantee')
->label('Add Guarantee')
->reactive()
->live()
->dehydrated(false) // Don't persist this field
->afterStateHydrated(function ($component, $state, $record) {
// Only set the state if it is null (i.e., first hydration)
if (is_null($state)) {
$component->state((bool) ($record?->guarantor_id));
}
})
->afterStateUpdated(function ($state, $set) {
if (!$state) {
$set('guarantor_id', null); // Clear related field when unchecked
}
}),
Explanation
- afterStateHydrated:
- Only sets the checkbox state if it is
null(meaning the user hasn’t interacted yet, and the form hasn’t been submitted/validated). - This ensures the checkbox is checked if
guarantor_idexists, but only on the initial load.
- Only sets the checkbox state if it is
- afterStateUpdated:
- When the checkbox is unchecked, it sets
guarantor_idtonull.
- When the checkbox is unchecked, it sets
Why not use default()?
default()only applies on create, not on edit.- On edit, the form state is already set from the record, so
default()is ignored.
Why not always set state in afterStateHydrated?
- Because it would override user input after validation errors or when the form is rehydrated for any reason.
Summary:
This approach ensures the checkbox is checked on edit if guarantor_id exists, but after the user interacts, their choice is always respected.
Let me know if you need a full field group example or further clarification!