F
Filament3w ago
alan

Unexpected Dehydration of Hidden Fields with statePath

Why are fields that are hidden and located inside a Section with a statePath dehydrated, and how can this be avoided (while still using statePath)? Normally, hidden inputs should be hidden. Or not? Example:
protected function handleRecordCreation(array $data): Model
{
Log::info(json_encode($data, JSON_PRETTY_PRINT));
dd($data);
}

public function form(Form $form): Form
{
return $form->schema([
Section::make("Your Information")->schema([
TextInput::make('name')->label("Your Name (for section)")->default('test')->hidden(),
])
->columns(2)
->statePath('data'),
]);
}
protected function handleRecordCreation(array $data): Model
{
Log::info(json_encode($data, JSON_PRETTY_PRINT));
dd($data);
}

public function form(Form $form): Form
{
return $form->schema([
Section::make("Your Information")->schema([
TextInput::make('name')->label("Your Name (for section)")->default('test')->hidden(),
])
->columns(2)
->statePath('data'),
]);
}
=> log:
array:1 [
"data" => array:1 [
"name" => "test"
] // (not correct)
]
array:1 [
"data" => array:1 [
"name" => "test"
] // (not correct)
]
without state Path:
protected function handleRecordCreation(array $data): Model
{
Log::info(json_encode($data, JSON_PRETTY_PRINT));
dd($data);
}

public function form(Form $form): Form
{
return $form->schema([
Section::make("Your Information")->schema([
TextInput::make('name')->label("Your Name (for section)")->default('test')->hidden(),
])
->columns(2),
//->statePath('data'), statePath removed
]);
}
protected function handleRecordCreation(array $data): Model
{
Log::info(json_encode($data, JSON_PRETTY_PRINT));
dd($data);
}

public function form(Form $form): Form
{
return $form->schema([
Section::make("Your Information")->schema([
TextInput::make('name')->label("Your Name (for section)")->default('test')->hidden(),
])
->columns(2),
//->statePath('data'), statePath removed
]);
}
log:
[] // (correct)
[] // (correct)
20 Replies
alan
alanOP2w ago
Does anybody have a clue? Anyone? Sadly I haven't found any more information about this in the documentation. I don't know where to look any further. Does anyone have any idea?
Bruno Pereira
Bruno Pereira2w ago
the inputs that are hidden in the html still go with the request. Thats normal behaviour. In fact thats how laravel handles the crsf token in the forms.
Bruno Pereira
Bruno Pereira2w ago
if your objective is to not have the input in the request, you should use ->disabled() https://filamentphp.com/docs/3.x/forms/fields/getting-started#disabling-a-field
Dennis Koch
Dennis Koch2w ago
Yes, but they aren’t type="hidden" inputs. They are hidden by filament.
Bruno Pereira
Bruno Pereira2w ago
yeah you're right. I thought that the hidden() would do that. Well ignore my message then xD I tested it and the hidden() removes the input from the dom and the Hidden form component makes the input type hidden. Today I learned 😄
alan
alanOP2w ago
Yes, but still, if I use ->hidden() on an input and this is in a section with a state path, then it is still sent and saved in the db even though it is hidden. Isn't that a bug? Unfortunately, I have to ask again. The problem is that as soon as something has a state path, the hidden property is ignored and the information from the input field is stored in the database. Is there a fix for this (without using mutate on create or similar, because I have a lot of these fields)?
return $form->schema([
Section::make("Your Information")->schema([
TextInput::make('name')->label("Your Name (for section)")->default('test')->hidden()->dehydratedWhenHidden(false)->dehydrated(false),
])
->columns(2)
->statePath('data'),
]);
return $form->schema([
Section::make("Your Information")->schema([
TextInput::make('name')->label("Your Name (for section)")->default('test')->hidden()->dehydratedWhenHidden(false)->dehydrated(false),
])
->columns(2)
->statePath('data'),
]);
Even after adding ->dehydratedWhenHidden(false)->dehydrated(false) the value from the text input is still getting stored in the database 😢
Dennis Koch
Dennis Koch2w ago
@Dan Harrin Any idea why this might happen? Didn't have the time to dive deeper.
Dan Harrin
Dan Harrin2w ago
@alan are you in a standard Filament resource or is this your own form on a custom page / livewire component?
alan
alanOP2w ago
Its a standard filament resource
class CreateExample extends CreateRecord
{
protected static string $resource = ExampleResource::class;

protected function handleRecordCreation(array $data): Model
{
Log::info(json_encode($data, JSON_PRETTY_PRINT));
dd($data);
}

public function form(Form $form): Form
{
return $form->schema([
Section::make("Your Information")
->schema([
TextInput::make('name')
->default('test')
->hidden()
->dehydrated(false),
])
->statePath('data')
]);
}
}
class CreateExample extends CreateRecord
{
protected static string $resource = ExampleResource::class;

protected function handleRecordCreation(array $data): Model
{
Log::info(json_encode($data, JSON_PRETTY_PRINT));
dd($data);
}

public function form(Form $form): Form
{
return $form->schema([
Section::make("Your Information")
->schema([
TextInput::make('name')
->default('test')
->hidden()
->dehydrated(false),
])
->statePath('data')
]);
}
}
Dan Harrin
Dan Harrin2w ago
there are a lot of similar test cases for this sort of thing. eg https://github.com/filamentphp/filament/blob/3.x/tests/src/Forms/StateTest.php#L458-L474 what I am going to ask from you, alan, is to submit a pull request with a failing test similar to this one i will then resolve the issue in the same pull request and merge it
GitHub
filament/tests/src/Forms/StateTest.php at 3.x · filamentphp/filament
A collection of beautiful full-stack components for Laravel. The perfect starting point for your next app. Using Livewire, Alpine.js and Tailwind CSS. - filamentphp/filament
alan
alanOP2w ago
@Dan Harrin I created a pr https://github.com/filamentphp/filament/pull/16295 . Thank you for taking the time
GitHub
Hidden fields incorrectly dehydrated in Section with state path by ...
Description This PR addresses a bug where conditionally hidden fields within a Section component (with state path) are incorrectly dehydrated. Currently, when a field is both: Hidden based on a co...
alan
alanOP2w ago
Hi, I saw the fix and really appreciate how quickly it was done I have a follow-up question: In a Wizard step, when an input is marked as ->hidden(), Get still returns its value. Is this expected behavior? Here’s a example:
public function form(Form $form): Form
{
return $form
->schema([
Wizard::make([
Step::make('step1')
->schema([
TextInput::make('name')
->required()
->default('lorem ipsum')
->maxLength(255)
->hidden()
])
->afterValidation(function (Get $get) {
dd($get('name')); // returns "lorem ipsum" even though the input is hidden
}),
...
])
]);
}
public function form(Form $form): Form
{
return $form
->schema([
Wizard::make([
Step::make('step1')
->schema([
TextInput::make('name')
->required()
->default('lorem ipsum')
->maxLength(255)
->hidden()
])
->afterValidation(function (Get $get) {
dd($get('name')); // returns "lorem ipsum" even though the input is hidden
}),
...
])
]);
}
My goal is to save data step-by-step when editing a record (that already works). But I want hidden inputs to not be saved (or set to null). Since Get always returns a value—even when hidden (and even with dehydrated(false)) - this breaks that logic, because thats how I get the values and save them later. Is there a way to handle this? Thanks in advance
Dan Harrin
Dan Harrin2w ago
Yes its expected because its useful to know what it stores if an input is conditonally hidden you can run that same condition check yourself if you want to obey it
alan
alanOP2w ago
Is there a simpler way to do this without repeating code? I want to save data after each step - even if other required fields aren't filled in yet (this already works). If something is hidden, it should store null for the key (that doesn't work for now). With this solution I'd need to duplicate a lot of code, especially with nested repeaters and complex hidden logic. Is there a better solution?
Step::make('step1')
->schema([
TextInput::make('name')
->required()
->default('lorem ipsum')
->maxLength(255)
->hidden(/* my complicated logic */)
])
->afterValidation(function (Get $get, Model $record) {
$data = $record->data ?? [];

// Value is saved even if hidden; I'd like to avoid writing an `if` check here
$data['name'] = $get('name');

$record->data = $data;
$record->save();
}),
Step::make('step1')
->schema([
TextInput::make('name')
->required()
->default('lorem ipsum')
->maxLength(255)
->hidden(/* my complicated logic */)
])
->afterValidation(function (Get $get, Model $record) {
$data = $record->data ?? [];

// Value is saved even if hidden; I'd like to avoid writing an `if` check here
$data['name'] = $get('name');

$record->data = $data;
$record->save();
}),
Dennis Koch
Dennis Koch2w ago
Something like this could work:
->afterValidation(function (Model $record, $data, $component) {
$newData = $record->data;
$key = $component->getName();
$newData[$key] = $data[$key];

$record->data = $newData;
$record->save();
}),
->afterValidation(function (Model $record, $data, $component) {
$newData = $record->data;
$key = $component->getName();
$newData[$key] = $data[$key];

$record->data = $newData;
$record->save();
}),
alan
alanOP2w ago
Thanks for the tip, but unfortunately that doesn't work
Method Filament\Forms\Components\Wizard\Step::getName does not exist.
Method Filament\Forms\Components\Wizard\Step::getName does not exist.
on this line:
$key = $component->getName();
$key = $component->getName();
Dennis Koch
Dennis Koch2w ago
Ah, you have it on the Step. Sorry, I thought it's on the Input. But do you get $data ? Then you could just manually remove unwanted values
alan
alanOP2w ago
Yes I get $data. But I would like to avoid nulling hidden data manually because I have nested repeaters and that means unnecessary complexity. I have a form with 300 input fields and many toggle buttons with visibility on other sections
Dennis Koch
Dennis Koch2w ago
But hidden fields shouldn't be included in $data. Isn't that what Dan just fixed? You used $data from the callback?
Dan Harrin
Dan Harrin2w ago
where is $data injected in a wizard? i dont see it

Did you find this page helpful?