Textinput value like Placeholder content?
In Placeholder::make('name')->content() I can "listen" to the other live() fields of the form and dynamically change the value of content depending on the other fields. How to do similarly with the value of the Textinput field? I know that during form initialization I can use ->default() but I am concerned with editing the form.
19 Replies
You can use a standard closure for the content:
You'll find more examples in the docs, many methods can work like this:
https://filamentphp.com/docs/3.x/forms/getting-started#dependant-fields
I know how to do it with Placeholder, however, my question is about TextInput. How do you fill a TextInput with a value just like you fill a Placeholder with ->content()? Method ->content() doesn't exist for TextInput.
Ok, my bad, I did miss the point of the question. It's a bit different with input fields, you'll need to use
afterStateUpdated()
and $set()
. Check the second example in the link I shared 👆hmmm... And there is no way to get data from other fields using $get to this field? That would be much more convenient because it would be done from one place.
When injecting data from other fields ($set), you have to perform an action on each of those fields, so a lot more operations.
Also (and this is the worst), afterStateUpdated only works with user input. It doesn't work with data coming from $set and php (so says the documentation). There are times when the data comes from $set or PHP, what then?
I'm a bit confused because awcodes recently wrote that it is possible to reverse using afterStateHydrated, i.e. retrieve data with $get and not transfer from other fields with $set. https://discord.com/channels/883083792112300104/1143657714086580264/1144196863428399177 Unfortunately either I misunderstood this or it doesn't work. The topic is died, probably because I clicked "Solved" too soon 🙂
I'm a bit confused because awcodes recently wrote that it is possible to reverse using afterStateHydrated, i.e. retrieve data with $get and not transfer from other fields with $set. https://discord.com/channels/883083792112300104/1143657714086580264/1144196863428399177 Unfortunately either I misunderstood this or it doesn't work. The topic is died, probably because I clicked "Solved" too soon 🙂
I think there are probably a couple of different ways to approach this, but I don't have enough information on what you're trying to do exactly.
afterStateHydrated()
is a good hook but it's only executed once, when the form is initialized.
I agree with you that $get()
and $set()
is not always super convenient when a form is very dynamic, but it works.In this example I can put qty or price manually and Total is calculated. I can even use Select to send price by $set and Total is calculated live... I want the same but with Textinput, not Placeholder
public static function form(Form $form): Form
{
return $form
->schema([
Select::make('Product')->options([1 => 'product1', 2 => 'product2', 3 => 'product3'])
->afterStateUpdated(
function($state, $set) {
if ($state == 1) $set('price',221);
elseif ($state == 2) $set('price',332);
elseif ($state == 3) $set('price',445);
})->live(),
TextInput::make('qty')->live(),
TextInput::make('price')->live(),
Placeholder::make('total')
->content(function (Get $get) {
return $get('qty') * $get('price');
})
]);
}
Do you want your users to be able to edit the TextInput?
Yes, sometimes TextInput will be disabled() (just for total preview), sometimes user should edit it manually. Of course, in this particular case it does not make sense, but I have other such cases where it is needed.
In this example, even if I used afterStateUpdated() on the qty and price fields, sending the result using $set('total') then there are 2 problems:
1. I have to repeat the same action 2 times on both fields and send the result to total
2. Select won't work here (because afterStateUpdated() only works when entering the price manually.
If you're worried about duplication, you can always extract the closure:
Oh lol. Didn't see there were answers already 🤦🏼♂️
The more the merrier 😄
Yes, admittedly it can be simplified but these fields are sometimes more than 2.... Well, and the Select field would also need to be extended by another recalculation, because just sending the price to the price field is not enough, you also need to send the result here to the total. It gets a bit complicated, I wonder, from a technical point of view, why in Placeholder it can be done with $get in ->content() and with TextInput it can't? Why doesn't TextInput have a method such as ->value() ?
@qcol You can apply the same idea for the Select:
Why doesn't TextInput have a method such as ->value() ?Because it's not that simple i guess... there are already
->default()
->afterStateHydrated()
->formatStateUsing()
... where does ->value()
fit into this?but ->default() and ->afterStateHydrated() work only when form is initiated?
Sure, but I still don't know where
->value()
would fit in the field's lifecycle
If you have some time, I guess you could try to work on TextInput, see if you can extend it to fit your use-case. If you find a great solution, send a PR. It's possible that it can be improved.OK, Thank you very much for your help, now I know for sure that I have to do it differently. I thought there was something I didn't know or something I was doing wrong. Time to get to work. Thanks again! 🙂
You're welcome!
Oh, I'm too weak for such things.... Maybe someday? 🙂