Certainly! This is a common scenario when using Filament forms with "virtual" fields that are not persisted, but need to be initialized based on the record. The core of your problem is that afterStateHydrated (and even default) will run on every hydration, not just the initial mount, and $record may not reflect the latest form data after submission.
The recommended Filament approach is to use the default() method for initial state, and avoid using afterStateHydrated for this purpose.
However, you must ensure that the default only applies on the very first load, and does not override user input on subsequent hydrations.
Solution
Use default() with a closure, and remove afterStateHydrated.
Filament will only use the default() value if there is no value in the form state (i.e., on first load or when creating a new record).
After the user interacts with the checkbox, their input will be respected, and the checkbox will not be re-checked on subsequent renders.
Example:
Checkbox::make('add_guarantee')
->label('Add Guarantee')
->reactive()
->live()
->dehydrated(false)
->default(fn ($record) => !blank($record?->guarantor_id))
->afterStateUpdated(function ($state, $set) {
if (!$state) {
$set('guarantor_id', null);
}
}),
Explanation:
default(fn ($record) => !blank($record?->guarantor_id))
This will pre-check the checkbox only on the initial load if the record has aguarantor_id.
After the user interacts with the checkbox, their input is preserved in the Livewire state, and the default is ignored.- Remove
afterStateHydratedentirely.
It is not needed for this use case and causes the re-checking issue. dehydrated(false)ensures the checkbox is not saved to the database.afterStateUpdatedclearsguarantor_idwhen the checkbox is unchecked.
Why default works (and afterStateHydrated does not)
defaultonly sets the initial value if the field is not already set in the Livewire state.afterStateHydratedruns on every hydration, including after form submission, and can override user input.
If you need to support "reset" actions
If you have a "reset" button or similar, and want to re-initialize the checkbox, you may need to handle that separately (e.g., by resetting the form state).
Summary:
- Use
defaultfor initial state. - Remove
afterStateHydrated. - Your checkbox will now only be pre-checked on first load, and will respect user changes after that.
Let me know if you need further clarification!