`formatStateUsing` not working when fields are loaded dynamically

Hi. I'm loading fields dynamically based on a select like this: https://filamentphp.com/docs/3.x/forms/advanced#dynamic-fields-based-on-a-select-option. However I can't get formatStateUsing to work when switching select options. It only works for the fields of the option that's selected when the page loads. Anyone know why?
4 Replies
Dennis Koch
Dennis Koch4mo ago
Can you share some code?
binaryfire
binaryfire4mo ago
Sure. So what I'm trying to do is use formatStateUsing to turn a TextInput into a placeholder that users can copy a value from:
public function form(Form $form): Form
{
return $form
->schema([
Section::make('API provider')
->schema([
Select::make('provider')
->options(ApiProvider::class)
->native(false)
->required()
->live(),

Group::make()
->schema(function (Get $get) {
return match((int) $get('provider')) {
ApiProvider::PROVIDER_ONE->value => $this->getProviderOneFields(),
ApiProvider::PROVIDER_TWO->value => $this->getProviderTwoFields(),
default => [],
};
})
])
])
->statePath('data');
}

private function getProviderOneFields(): array
{
return [
TextInput::make('provider_data.provider_one.api_key')
->label('API key')
->required(),

TextInput::make('provider_one_callback_url')
->label('Callback URL')
->hint('Copy this into your API provider\'s "Callback URL" field')
->formatStateUsing(fn () => route('provider_one.callback'))
->suffixAction(CopyAction::make())
->readonly()
->dehydrated(false),
];
}
public function form(Form $form): Form
{
return $form
->schema([
Section::make('API provider')
->schema([
Select::make('provider')
->options(ApiProvider::class)
->native(false)
->required()
->live(),

Group::make()
->schema(function (Get $get) {
return match((int) $get('provider')) {
ApiProvider::PROVIDER_ONE->value => $this->getProviderOneFields(),
ApiProvider::PROVIDER_TWO->value => $this->getProviderTwoFields(),
default => [],
};
})
])
])
->statePath('data');
}

private function getProviderOneFields(): array
{
return [
TextInput::make('provider_data.provider_one.api_key')
->label('API key')
->required(),

TextInput::make('provider_one_callback_url')
->label('Callback URL')
->hint('Copy this into your API provider\'s "Callback URL" field')
->formatStateUsing(fn () => route('provider_one.callback'))
->suffixAction(CopyAction::make())
->readonly()
->dehydrated(false),
];
}
There's no attribute called provider_one_callback_url. That's just a random name I gave the placeholder field. The field is just for displaying the copyable URL. formatStateUsing(fn () => route('provider_one.callback')) works if the field is already set to Provider One when the page loads, but it doesn't work when the fields are loaded dynamically (eg. if Provider Two was selected and then I change the select to Provider One). Or maybe there's another way to hardcode the initial state of the field?
Dennis Koch
Dennis Koch4mo ago
I think the important part of the example is that afterStateUpdated() call that fills the form fields.
binaryfire
binaryfire4mo ago
Ah that makes sense. So it's not really gonna work then... Probably easier to just make a custom field