F
Filament•11mo ago
Albert Lens

Reuse the form schema in resource to call it from action buttons around

Hello. I am using Select::make('field_name') with the options of createOptionForm and also editOptionForm and I would like to: change the icon of the plus sign place it before the field instead of after it Be able to translate the text "create option" that appears when hovering over. Any idea if these are possible and how? Thank you.
No description
27 Replies
Patrick Boivin
Patrick Boivin•11mo ago
Not sure if you can change the position but I think you can change the icon and the tooltip
Albert Lens
Albert Lens•11mo ago
Have gone through this document several times fully and have found nothing of tooltip or icon for the →createOptionForm()
No description
toeknee
toeknee•11mo ago
->createOptionAction( fn (Action $action) => $action->modalWidth('3xl')->icon('my-icon'), ) It should function like the other actions, but I haven't used it
Albert Lens
Albert Lens•11mo ago
Ok. Tks Will try to find an example of Action which opens the resource CREATE form in a modal, but someone told me the other day that was NOT possible. Hope someone finds a solution, cause we would be able to call the create or edit resource standard form without having to write all the fields, validations, layouts, etc. again.
awcodes
awcodes•11mo ago
Just make a method on the resource that returns the array of form fields. Then you can call that method off the resource anywhere you need to recreate the form.
Albert Lens
Albert Lens•11mo ago
That sounds great! Is there any example you could please link, or doc? Tks a lot.
Patrick Boivin
Patrick Boivin•11mo ago
@albertlens Maybe this can help https://discord.com/channels/883083792112300104/883083792653381695/1119602235043749948 The context is different but the solution is the same
Albert Lens
Albert Lens•11mo ago
Right. I have done this: In a form (EstateType) where I choose people from a Select dropdown, I want to have a CreatePerson Button (making profit of the form that I already have in PersonResource::form).
->schema([
Actions::make([
Action::make('CreatePerson')
->action(fn()=>PersonResource::form($form))
])
->columnSpanFull(),
TextInput::make('description') ... etc.
->schema([
Actions::make([
Action::make('CreatePerson')
->action(fn()=>PersonResource::form($form))
])
->columnSpanFull(),
TextInput::make('description') ... etc.
When I click the CreatePerson BUTTON it REALLY OPENS the create person form, but NOT MODAL (or at least it ocuppies the whole screen) hiding all the fields of the EstateType form. Also, the most important part is, it does NOTHING. When I choose something and it has to recalculate or fill full name with name + surname, etc. it closes and goes back to the EstateType form with no warning. I suppose I am missing an important part. Sorry for being so newbie in this. Something like:
$person = new Person();
$person->fill($data);
$person->save();
$person = new Person();
$person->fill($data);
$person->save();
But I do not know where or how to tell the system to do this.
Patrick Boivin
Patrick Boivin•11mo ago
At a glance, ->action() is probably the issue. Have you tried ->form() instead?
Albert Lens
Albert Lens•10mo ago
Same result. I give up. I cannot get it to work.
return $form
->schema([
Actions::make([
Action::make('CreatePerson')
->form(fn()=>PersonResource::form($form))

])->columnSpanFull(),
return $form
->schema([
Actions::make([
Action::make('CreatePerson')
->form(fn()=>PersonResource::form($form))

])->columnSpanFull(),
I have a resource called PersonResource. I have quite a lot of field defined there and that resource by itself (create, edit, etc.) is working great. Now I would like to put a button in some places around the application, for example, EstateTypeResource (create) to let the user pop up a modal with the new Person form. I am unable to do it. I have been making different tests for more than 8 hours with no results. It would be very useful because now I am just beginning the development of the app which will be long and big and this would save me a lot of future time. The picture I would like is something like the image.
No description
awcodes
awcodes•10mo ago
Maybe this will help. 🙂
// PersonResource.php
public static function form(Form $form): Form
{
return $form
->schema(static::getFormFields());
}

public static function getFormFields(): array
{
return [
Forms\Components\TextInput::make('foo'),
Forms\Components\TextInput::make('bar'),
];
}

// Action
Actions::make([
Action::make('CreatePerson')
->form(PersonResource::getFormFields())
->action(function($data) {
PersonResource::getModel()->create($data);
}),
])
// PersonResource.php
public static function form(Form $form): Form
{
return $form
->schema(static::getFormFields());
}

public static function getFormFields(): array
{
return [
Forms\Components\TextInput::make('foo'),
Forms\Components\TextInput::make('bar'),
];
}

// Action
Actions::make([
Action::make('CreatePerson')
->form(PersonResource::getFormFields())
->action(function($data) {
PersonResource::getModel()->create($data);
}),
])
awcodes
awcodes•10mo ago
Albert Lens
Albert Lens•10mo ago
Yes. I know. And I am using that already. But that implies I have to repeat all the schema of fields, sections and everything inside the ->createOptionForm([ For that reason I was trying to REUSE the schema of the form inside the PersonResource to save time, to keep one only schema updated with changes the customer needs, etc. Thanks anyway and I will have to retype all fiels inside the ->createOptionForm([ (or copy & paste).
awcodes
awcodes•10mo ago
no you don't
Albert Lens
Albert Lens•10mo ago
I'll revise. It looks fine.
awcodes
awcodes•10mo ago
->createOptionForm(PersonResource::getFormFields())
Albert Lens
Albert Lens•10mo ago
Is it that simple? I must be stupid, sorry. I'll test it immediately and come back with result.
awcodes
awcodes•10mo ago
yes it is that simple as long as you define a static method for the form fields and return an array of the form fields you need you can call them off of that class anytime you need to use the array of form fields. and it doesn't have to be on the PersonResouce. it works the same with any class. that's just OOP. just makes sense in your case to put it on the PersonResource I do this all the time when i want to have a full edit page but a modal for creating a new record
Albert Lens
Albert Lens•10mo ago
Thanks a lot. You have saved me a lot of future time, I believe. The ->createOptionForm(PersonResource::getFormFields()) works incredibly fine. But, abusing your help, for the Action button, I am getting a strange error with the example code you gave me:
Actions::make([
Action::make('CreatePerson')
->form(PersonResource::getFormFields())
->action(function($data) {
PersonResource::getModel()->create($data);
}),
]),
Actions::make([
Action::make('CreatePerson')
->form(PersonResource::getFormFields())
->action(function($data) {
PersonResource::getModel()->create($data);
}),
]),
I am getting this error: Expected type 'object'. Found 'string'. Please see picture.
No description
awcodes
awcodes•10mo ago
my bad, try this
Action::make('blah')
->model(PersonResource::getModel())
->form(PersonResource::getFormFields())
Action::make('blah')
->model(PersonResource::getModel())
->form(PersonResource::getFormFields())
might need to use a CreateAction for that to work though, instead of a regular Action.
Albert Lens
Albert Lens•10mo ago
Ok. I'll try and be back. Tks again.
Albert Lens
Albert Lens•10mo ago
It is not working either. It thows: Filament\Forms\Components\Actions::Filament\Forms\Components{closure}(): Argument #1 ($action) must be of type Filament\Forms\Components\Actions\Action, Filament\Actions\CreateAction given It looks as if, according to offical docs https://filamentphp.com/docs/3.x/actions/prebuilt-actions/create#overview CreateAction cannot be used within the fields schema of a FORM. It looks as if it is only for tables. May that be true? Is CreateAction only for Tables?
Albert Lens
Albert Lens•10mo ago
My code now is:
return $form
->schema([
Actions::make([
CreateAction::make('CreatePerson')
->form(PersonResource::getFormFields())
->model(PersonResource::getModel())
]),
return $form
->schema([
Actions::make([
CreateAction::make('CreatePerson')
->form(PersonResource::getFormFields())
->model(PersonResource::getModel())
]),
awcodes
awcodes•10mo ago
Makes sense. To use an an action as a CreateAction then you’ll need to handle the creation in the ->action() method. One of the benefits of using creatOptionForm() it handles it all for you. Don’t over complicate it unless you absolute need to. And since you want to create a record that is also a value in the select that’s exactly what createOptionForm() was made for.
Albert Lens
Albert Lens•10mo ago
You're absolutely right. The main logic is to create a new element for a select on the go, and this is absolutely achieved with ->createOptionForm(). The rest is just over complicating just for the eager to know more tecniques which will be logical in a tables context. Thanks again for your help.
erikms61
erikms61•8mo ago
Hi, I'm not sure if I'm breaking etiquette by replying to this old thread, but I have a similar problem as Albert. I managed to get pretty far in solving it, but now I seem to be stuck. I have a LocationRescource, with an Action on the table rows to replenish stock at the Location. When the action is triggered, this creates an Activity. I then want the user to be able to edit the Activity, re-using the ActivityResource form fields. So far so good. However, the Activity form contains relationships, and somehow these cannot deal with relationships on the Activity object. //LocationResource.php Action::make('Restock') ->model(ActivityResource::getModel()) ->form([ TextInput::make('description'), DatePicker::make('due_date'), DatePicker::make('planned_date'), TextInput::make('priority')->numeric(), Select::make('status_id')->options( ActivityStatus::all()->pluck('name', 'id') )->relationship('Status', 'name'), ]) ->mountUsing(function (Form $form, LocationStock $record) { $activity = $record->replenish(); $form->fill($activity->toArray()); }), If I remove the Select from the form, everything is fine. Put it in, I get "Call to a member function getResults() on null" Any ideas?