create records view. How add another custom button

In my create product view, I want to add a custom button "Generate product variants", when my own custom function to handle that button click. How can I do that?
35 Replies
Dennis Koch
Dennis Koch6mo ago
You'd need to overwrite the action (or use ->after()) and add an action via ->modalFooterActions()
atabegruslan
atabegruslanOP6mo ago
Can you please share the documentation links for overwrite the action or ->after(). I am not sure which one it is
No description
No description
atabegruslan
atabegruslanOP5mo ago
Im going to need more help with this. Where do you write this code? In the resource file or one of the page files? https://filamentphp.com/docs/3.x/actions/modals#adding-an-extra-modal-action-button-to-the-footer
Dennis Koch
Dennis Koch5mo ago
The CreateAction is a in getHeaderActions on the ListPage
atabegruslan
atabegruslanOP5mo ago
Actually. I dont get how this should work. See screenshot. With or without that code block, I see the same view, with the same "create another" button
No description
gladjanus43
gladjanus435mo ago
On your CreateProducts.php you can add the function
protected function getFormActions(): array
{
return [];
}
protected function getFormActions(): array
{
return [];
}
https://filamentphp.com/docs/3.x/panels/resources/creating-records#custom-actions Here the show how to extend the default buttons
atabegruslan
atabegruslanOP5mo ago
How do I keep the cancel button?
gladjanus43
gladjanus435mo ago
I think $this->getCancelFormAction(),
Dennis Koch
Dennis Koch5mo ago
Sorry, thought it's a CreatAction not a page
atabegruslan
atabegruslanOP5mo ago
I finally got something like this
/*
$this->data
array:4 [
"name" => "xxxx"
"category_id" => "1"
"thumbnail" => array:1 [▶]
"variants_outline" => "yyyy"
]
*/

protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants'),
Actions\Action::make('Save product')->action('save'),
$this->getCancelFormAction(),
];
}
public function generateVariants(): void
{
print_r($this->data);
}
/*
$this->data
array:4 [
"name" => "xxxx"
"category_id" => "1"
"thumbnail" => array:1 [▶]
"variants_outline" => "yyyy"
]
*/

protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants'),
Actions\Action::make('Save product')->action('save'),
$this->getCancelFormAction(),
];
}
public function generateVariants(): void
{
print_r($this->data);
}
Now in my generateVariants method, if one of the fields doesnt match a certain format, how can I return validation error?
gladjanus43
gladjanus435mo ago
I think that is just a validation on your form itself right?
atabegruslan
atabegruslanOP5mo ago
What do you mean by "my form"? Currently in the ProductResource
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Textarea::make('name')
->required()
->columnSpanFull(),
Forms\Components\Select::make('category_id')
->required()
->relationship('category', 'name'),
Forms\Components\FileUpload::make('thumbnail')
->required()
->image(),
Forms\Components\Textarea::make('variants_outline')
->hint('Please outline your product variations in the following format: size:small,large,extra_large;color:red,blue . If the product have no variations, then leave this empty.')
->regex('/[A-Za-z0-9_]+:[A-Za-z0-9_]+(,[A-Za-z0-9_]+)+(;[A-Za-z0-9_]+:[A-Za-z0-9_]+(,[A-Za-z0-9_]+)+)+/i') // Todo: decide to have regex here or in CreateProduct
->columnSpanFull(),

]);
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Textarea::make('name')
->required()
->columnSpanFull(),
Forms\Components\Select::make('category_id')
->required()
->relationship('category', 'name'),
Forms\Components\FileUpload::make('thumbnail')
->required()
->image(),
Forms\Components\Textarea::make('variants_outline')
->hint('Please outline your product variations in the following format: size:small,large,extra_large;color:red,blue . If the product have no variations, then leave this empty.')
->regex('/[A-Za-z0-9_]+:[A-Za-z0-9_]+(,[A-Za-z0-9_]+)+(;[A-Za-z0-9_]+:[A-Za-z0-9_]+(,[A-Za-z0-9_]+)+)+/i') // Todo: decide to have regex here or in CreateProduct
->columnSpanFull(),

]);
if that answers your q I bothers me that the handler function generateVariants(): void returns void. So this approach is a dead end if I want validation?
gladjanus43
gladjanus435mo ago
Can you tell a bit what you are exactly trying to acchieve with the function?
atabegruslan
atabegruslanOP5mo ago
You know in a typical eCommerce website, when shopkeeper enters a new product (with variants) in the backoffice, he enters the product name, desc... then he write out the product variant's attributes and values, then he clicks Generate Product Variants button, then after the backend generates all the variants, the shopkeeper can go in and fill in all the skus, prices, images, ... for all the variants, then he clicks save, and then the product and its variants are saved to the DB That's my intention ^ Too much customization for Filament to handle? Maybe I have to consider using beforeCreate and afterCreate again. Shopkeeper can generate the variants and save product and variants in the create phase. Then shopkeeper can then fill in the variant info in the edit phase. So unless someone have a better idea, that's my plan B
Dennis Koch
Dennis Koch5mo ago
You should use $this->form->getState() and not access $this->data directly. Have a look at the default save method and copy what you need That's a limitation you set yourself, right? Because the method was not defined before
atabegruslan
atabegruslanOP5mo ago
True. It doesnt have to be void Good idea Good idea. But where is this method? Should I dig for it in the vendors folder? Actually I cant find it. The closest I found is this, which isnt much
protected function getCreateFormAction(): Action
{
return Action::make('create')
->label(__('filament-panels::resources/pages/create-record.form.actions.create.label'))
->submit('create')
->keyBindings(['mod+s']);
}
protected function getCreateFormAction(): Action
{
return Action::make('create')
->label(__('filament-panels::resources/pages/create-record.form.actions.create.label'))
->submit('create')
->keyBindings(['mod+s']);
}
Dennis Koch
Dennis Koch5mo ago
When you have a good editor or IDE you usually can do a "Symbol search". Open the create page and search for the create method. It's on the Filament\Resources\Pages\CreateRecord.
No description
atabegruslan
atabegruslanOP5mo ago
Thank you, that really helped A follow up Q pls. How can you do something like this?
atabegruslan
atabegruslanOP5mo ago
No description
LeandroFerreira
LeandroFerreira5mo ago
Textarea::make('variants_outline')
->live(debounce: 500)
Textarea::make('variants_outline')
->live(debounce: 500)
CreatePage
protected function getCreateFormAction(): Action
{
return parent::getCreateFormAction()
->disabled(fn () => blank($this->data['variants_outline']));
}
protected function getCreateFormAction(): Action
{
return parent::getCreateFormAction()
->disabled(fn () => blank($this->data['variants_outline']));
}
atabegruslan
atabegruslanOP5mo ago
Very helpful. Thank you. But getCreateFormAction gets the default save button (wouldnt it?). The "Generate variants" button in my screenshot is a custom button (and event handler function) that I wrote, like this
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants'),
...
];
}
public function generateVariants()
{

}
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants'),
...
];
}
public function generateVariants()
{

}
awcodes
awcodes5mo ago
Shouldn’t it be $this->generateVarients()? Unless the method is a registered action it won’t be available by name. So it needs to be an actual callback.
atabegruslan
atabegruslanOP5mo ago
Not sure if I understood you correctly. But you mean I should disable the "Generate Variant" button in the public function generateVariants() method? But how do I get a handle on the "Generate Variant" button? I cant use parent::getCreateFormAction() to grab the button
awcodes
awcodes5mo ago
Well, your code doesn’t show anything about the default create action? So not sure I can answer your question. Seems like you are trying to chain onto the create action when an observer / job would make more sense. But you can override the default save action if you choose to do so. Just make sure you also handle the save logic implicitly.
atabegruslan
atabegruslanOP5mo ago
I am not using getCreateFormAction. Im not planning to use getCreateFormAction, because what Im planning to do is very custom. Both of the first 2 buttons are custom. This idea looks nice, I just wish to know how to apply it to my case Heya. My question is quite simple. In case you misunderstood my question to be something more complicated, I'll ask another way: If this is how you disable the default save button getCreateFormAction()->disabled(true), then how can you disable a custom button?
awcodes
awcodes5mo ago
You provide a callback function to the ->disabled() method. The code you have been sharing doesn’t align to the questions you are asking. So it’s difficult for us to give you an answer.
atabegruslan
atabegruslanOP5mo ago
Ok. I hope this helps
No description
awcodes
awcodes5mo ago
generateVariants isn't registered as an action so you can't call it by name.
->action($this->generateVariants())
->action($this->generateVariants())
`
atabegruslan
atabegruslanOP5mo ago
So $this->action($this->generateVariants()) this is the only way to "get a handle" on my custom generate variants button? did I understand you right?
awcodes
awcodes5mo ago
Did you try it? Does it even work?
atabegruslan
atabegruslanOP5mo ago
Actually no. I looked at my code again. There is no place to put such codes. Im open to other ideas
gladjanus43
gladjanus435mo ago
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action(
self::generateVariants();
),
...
];
}
public static function generateVariants()
{

}
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action(
self::generateVariants();
),
...
];
}
public static function generateVariants()
{

}
I think like this?
atabegruslan
atabegruslanOP5mo ago
This is just a syntax change But on a positive note, I finally figured out where and how to disable custom buttons
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants')->disabled(true),
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants')->disabled(true),
Thank you. I finally figured out how to apply this. It worked In CreateProduct page, I did
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants')->disabled(fn () => blank($this->data['variants_outline'])),
protected function getFormActions(): array
{
return [
Actions\Action::make('Generate Variants')->action('generateVariants')->disabled(fn () => blank($this->data['variants_outline'])),
In the ProductResource I did
class ProductResource extends Resource
{
protected static ?string $model = Product::class;

public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Textarea::make('variants_outline')
->live(debounce: 500),
class ProductResource extends Resource
{
protected static ?string $model = Product::class;

public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Textarea::make('variants_outline')
->live(debounce: 500),
gladjanus43
gladjanus435mo ago
Did not even know that was possible lol
Want results from more Discord servers?
Add your server