How to create custom actions and show them in custom views?

Hello, I've created a custom component for a custom view page where I want to show all the help tickets related to the current booking. I've successfully shown the records needed but I would also like to display a button in this component where it's possible to create a new ticket for that booking. I thought to do it using actions, but I can't understand how to build a custom action and how I can show it in a custom view. Thank you very much in advance for your help
72 Replies
awcodes
awcodes2y ago
#drop-in-action Assuming you’re in a form builder.
Gianmarco Varrone
No, I'm in the admin panel and I'm creating a custom ViewResource page. In this custome ViewResource page I have created a custom component where inside I successfully rendered a table component. Now, in the same component, I would like to show a custom button using action where I could show a modal to create a new ticket related to the current booking but I can't understand how to render and how to create a custom action.
awcodes
awcodes2y ago
Drop in action should still work for you. Not sure if it works in view resource but there is also suffix and prefix actions that can be used on specific fields. Every Action class has methods on it to use modals and forms and ways to interact with the ->action() method to process the data.
Gianmarco Varrone
I have followed the instructions on the plugin and tried to put the DropInAction inside the getActions() method of the viewBooking class but nothing Is rendered and no error in console. How should I render the component in the view?
awcodes
awcodes2y ago
It doesn’t go in the getActions. It’s used as a field in the form schema. If you’re wanting to just have an action in getActions then you don’t need a plugin. You can use regular Actions there.
Gianmarco Varrone
Oh ok, now i got your point about the drop in action! I will try it in the form schema.
awcodes
awcodes2y ago
And just register it in your ViewResource getActions method. Come down to where you’re trying to register the action. If you want it in the top right it’s a normal action inside getActions. If you want to have it inside a section or panel then you’ll need drop in action.
Gianmarco Varrone
I need it in a panel. So I can simply use it as form component and render it with $this->form using drop in action, from what I understand..
awcodes
awcodes2y ago
Honestly, still not 100% sure drop in works inside the view context. But in my head it should. Theoretically yes You just add it to the form schema as if it was a form input.
Gianmarco Varrone
And then, I can call on that action() all the methods I can find in the docs to interact with it...
awcodes
awcodes2y ago
Yes. It will be included in v3 out of the box.
Gianmarco Varrone
Thanks, I'll keep you posted on this! That would be wonderful!
awcodes
awcodes2y ago
No worries. Let me know. If it doesn’t work I can modify to work in the view context, maybe.
Gianmarco Varrone
Thanks a million! I'll post an update soon!
awcodes
awcodes2y ago
Just a weird situation to edit something from a view context. Seems counter intuitive but I can see a use case for it.
Gianmarco Varrone
Yes, it may see. But I have the right use case for it 😁 UPDATE: Drop in Action correctly renders the button on the component, but it seems it cannot open a modal. Even if call the form method() on the action within the needed fields and than call the requiresConfirmation() method on it. The loading spinner starts and suddenly stops and nothing happens. Is there anything I can do to make the pop up open?
toeknee
toeknee2y ago
I thought I just saw a post from you, did you solve it?
Gianmarco Varrone
No, sorry I wasn't able to find this one anymore and created a new one. Now I found this again and prefer to stick on this one without creating many posts. Here's the code that I'm using : protected function getFormSchema(): array { return [ DropInAction::make('test') ->disableLabel() ->execute(function (Closure $get, Closure $set) { return Action::make('create_ticket') ->icon('heroicon-o-plus') ->label('Nuovo ticket') ->action(fn () => null)->form([ TextInput::make("prova")->required() ])->requiresConfirmation(); }), ]; }
toeknee
toeknee2y ago
Ok pleae use the #❓┊help or the #drop-in-action as it gets too crowed in here
Gianmarco Varrone
How to use it?
toeknee
toeknee2y ago
How to use what? Got it now
Gianmarco Varrone
The tags. Sorry I'm not expert with discord. Just got how to use it
toeknee
toeknee2y ago
No problem
Gianmarco Varrone
#❓┊help #drop-in-action
toeknee
toeknee2y ago
two seconds I'll have a working example for you
Gianmarco Varrone
Thanks a million
toeknee
toeknee2y ago
DropInAction::make('test')
->disableLabel()
->execute(function (Closure $get, Closure $set) {
return Action::make('create_ticket')
->icon('heroicon-o-plus')
->label('Nuovo ticket')
->form([
TextInput::make('prova')->required(),
])
->requiresConfirmation()
->action(function () {
});
}),
DropInAction::make('test')
->disableLabel()
->execute(function (Closure $get, Closure $set) {
return Action::make('create_ticket')
->icon('heroicon-o-plus')
->label('Nuovo ticket')
->form([
TextInput::make('prova')->required(),
])
->requiresConfirmation()
->action(function () {
});
}),
Is a fully working example in our $form->schema[]); ensure your Action is an uses: use Filament\Forms\Components\Actions\Action;
Gianmarco Varrone
It seems to doesn't work for me😭 This is my full component : <?php namespace App\Http\Livewire\Booking; use Closure; use Filament\Forms; use Livewire\Component; use App\Models\PointOfSale; use Filament\Facades\Filament; use Illuminate\Support\Facades\Http; use Filament\Forms\Components\TextInput; use Http\Client\Exception\RequestException; use Filament\Forms\Components\Actions\Action; use Awcodes\DropInAction\Forms\Components\DropInAction; class CreateTicketAction extends Component implements Forms\Contracts\HasForms { use Forms\Concerns\InteractsWithForms; public $record; public function mount($record){ $this->record = $record; $this->address = "Via della Scrofa, 22, Roma"; } protected function getFormSchema(): array { return [ DropInAction::make('test') ->disableLabel() ->execute(function (Closure $get, Closure $set) { return Action::make('create_ticket') ->icon('heroicon-o-plus') ->label('Nuovo ticket') ->form([ TextInput::make('prova')->required(), ]) ->requiresConfirmation() ->action(function () { }); }), ]; } public function render() { return view('livewire.booking.create-ticket-action'); } }
toeknee
toeknee2y ago
If you inspect the browser, what does the console say?
Gianmarco Varrone
Absolutely nothing
toeknee
toeknee2y ago
What version of Filament?
Gianmarco Varrone
2.0
toeknee
toeknee2y ago
Please upgrade filament 2.0 is very old
Gianmarco Varrone
What's the latest version? The documentation says : "composer require filament/filament:"^2.0""
toeknee
toeknee2y ago
that's greater or equal than 2.0
Gianmarco Varrone
In my composer.json and composer.lock I've modified from "filament/filament" : ""^2.0"" to "filament/filament": " * ", but the is still not showing. Any suggestions?
toeknee
toeknee2y ago
You said you were on exactly 2.0
Gianmarco Varrone
oh sorry, so it was correct, my bad
toeknee
toeknee2y ago
you should be on like 2.17.17
Gianmarco Varrone
So i reverted back to the original version i had.
awcodes
awcodes2y ago
As I said it may not work in the view context. Not sure without looking at the core code, but the view context may not have the necessary modal renderer to allow this to work.
toeknee
toeknee2y ago
Ahh I missed this, it was working with the code I provided in my page form schema
Gianmarco Varrone
Got the point. I was surprised because @toeknee_iom said it was working for him. Is there a way i can create a modal renderer?
awcodes
awcodes2y ago
Not that world work this way out of the box. I’ll do some digging and get back to you later today.
toeknee
toeknee2y ago
you can use a normal method for rendering modals in livewire
awcodes
awcodes2y ago
Give me a few hours. Just waking up here.
Gianmarco Varrone
Take your time. Thanks a million! What do you mean?
toeknee
toeknee2y ago
rough example: https://tonylea.com/creating-modals-in-laravel-livewire But I'd wait for awcodes to see if he can do it for dropinaction first
Tony Lea - Developer and Designer from SoCal
Creating Modals in Laravel Livewire
In this tutorial I will show you how to create simple modals in Laravel Livewire. We are going to make use of an awesome package called LivewireUI Modal. This package allows you to create some re-usab...
Gianmarco Varrone
I will wait for him. Thanks for the moment
awcodes
awcodes2y ago
@gianmarcovarrone Just tired this with a one of my app and it's working fine. Make sure you are using the right Action. use Filament\Forms\Components\Actions\Action; Is your custom view page extending Filament's ViewRecord class?
Gianmarco Varrone
I think that I'm already using it..
awcodes
awcodes2y ago
right, that's just the component. what class are you using to render the whole page
Gianmarco Varrone
This the viewResource page that I'm using to render the custom view <?php namespace App\Filament\Resources\BookingResource\Pages; use Filament\Tables\Table; use Filament\Pages\Actions; use Filament\Tables\Contracts\HasTable; use App\Filament\Resources\BookingResource; use Filament\Tables\Concerns\InteractsWithTable; class ViewBooking extends ViewRecord implements HasTable { use InteractsWithTable; protected static string $resource = BookingResource::class; protected static string $view = 'filament.resources.booking-resource.pages.view-booking'; protected function getActions(): array { return [ // ]; } }
awcodes
awcodes2y ago
as a test, can you add ->modalHeading('test') to the action. i'm think it just doesn't know it needs to be a modal. everything looks ok, and it's work on a ViewRecord page for me.
awcodes
awcodes2y ago
Ok. something else is going on there. your code works in my page.
awcodes
awcodes2y ago
probably because it's a custom livewire component so it's not emitting up to the parent which has the listener for executing the Action.
Gianmarco Varrone
I think I'm missing something. Should I register this action in the getActions() of the view page? What type of event should I emit from the livewire component?
awcodes
awcodes2y ago
I think the problem is that ViewRecord, just like Create and Edit is a form, and your component is also rendering a form which you can't do in html. do you even need a custom component?
Gianmarco Varrone
What do you mean? What I'm trying to build is a component where the user can see all the help tickets related to the current booking, create a new one or post updates on existing tickets..
awcodes
awcodes2y ago
I just use the DropInAction in my form schema on the Resource, because it's also needed on Create and Edit Wouldn't that just be a Relation Manager?
toeknee
toeknee2y ago
I think from his screenshot, he want's to actually build a modal in a form in any place and not inside another form like you use DropInAction for
awcodes
awcodes2y ago
yea, it's clicking now. so actions don't work natively inside the main form on the page, that's why DropInAction was created. So to do it in a custom component, i'm thinking you'd have to implement your own modal and handle all the logic yourself. but it seems like to me this would just be a standard Relation Manager on a regular view record page.
Gianmarco Varrone
Yes, the issue is that no modal is shown. If I pass the data array to the actions() the action is executed correctly. But, if I use requireConfirmation() no modal is shown and no action is executed.
awcodes
awcodes2y ago
yea, because your component is a child livewire component. and the code that handles rendering modals is on the parent/page livewire component. so it never receives the event to show the modal.
Gianmarco Varrone
Yes, the relation manager would work. I should just place it in a component to fit in the screenshot above. Here's because I decided to go with custom component... So, the code that handles the modal is here protected static string $view = 'filament.resources.booking-resource.pages.view-booking'; right?
awcodes
awcodes2y ago
If that's where you're overriding the ViewRecord view to then yea.
Gianmarco Varrone
Well, not exactly there, sorry. I meant in the Class. Yes. So, I can avoid building a livewire component and simply use the code inside the main class ViewBooking to call the Drop In Action
awcodes
awcodes2y ago
ViewBooking, CreateBooking, EditBooking all use the same Page class, but you could just define the form schema on ViewBooking if you need it to be different than Create or Edit. When you define form schema on the BookingResource it's just used as a way to keep from repeating it all on the various record classes.
Gianmarco Varrone
I've updated my code. I deleted the child livewire component and tried to move all the code to the parent view. I moved my code for drop in action inside the getFromSchema() on the ViewBooking class as follow : ViewBooking Class <?php namespace App\Filament\Resources\BookingResource\Pages; use Closure; use Filament\Tables\Table; use Filament\Pages\Actions; use Filament\Forms\Contracts\HasForms; use Filament\Tables\Contracts\HasTable; use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\ViewRecord; use App\Filament\Resources\BookingResource; use Filament\Forms\Components\Actions\Action; use Filament\Forms\Concerns\InteractsWithForms; use Filament\Tables\Concerns\InteractsWithTable; use Awcodes\DropInAction\Forms\Components\DropInAction; class ViewBooking extends ViewRecord implements HasTable { use InteractsWithTable, InteractsWithForms; protected static string $resource = BookingResource::class; protected static string $view = 'filament.resources.booking-resource.pages.view-booking'; protected function getActions(): array { return [ // ]; } protected function getFormSchema(): array { return [ DropInAction::make('test') ->disableLabel() ->execute(function (Closure $get, Closure $set) { return Action::make('create_ticket') ->icon('heroicon-o-plus') ->label('Nuovo ticket') ->form([ TextInput::make('prova')->required(), ]) ->requiresConfirmation() ->action(function () { null; }); }), ]; } } This is how I'm rendering it in the blade view : <div> <div class="p-2 space-y-2 bg-white rounded-xl shadow dark:border-gray-600 dark:bg-gray-800"> <div> <div class="flex items-center justify-between gap-8 py-3"> <h2 class="text-lg font-semibold tracking-tight filament-card-heading"> Tickets </h2> {{$this->form}} </div> <div aria-hidden="true" class="filament-hr border-t dark:border-gray-700"></div> <div class="pt-2"> @livewire("booking.tickets", ["record"=>$record]) </div> </div> </div> </div> But I keep having the same issue as the video above 😅
awcodes
awcodes2y ago
is your blade view wrapped with <x-filament::page></x-filament::page>? also, trying my best here. i don't really have anything setup to test / troubleshoot with. sorry.
Gianmarco Varrone
No, It wasn't wrapped. I did wrap it and got the following error: Method Awcodes\DropInAction\Forms\Components\DropInAction::livewire does not exist. Ok the error disappeared. This is the view code : <x-filament::page> <div> <div class="flex"> <h1 class="filament-header-heading text-2xl font-bold tracking-tight mr-3"> {{$record->name}} </h1> <div> <span class="fi fi-{{$record->locale == "en" ? "gb" : $record->locale}} h-8 w-8 rounded-full" ></span> </div> </div> <div class="mt-4 lg:flex"> <div class="flex mr-3"> <x-heroicon-o-phone class="h5 w-5 shrink-0 mr-2"/> <a href="tel:{{$record->phone_number}}" class="text-primary-600">{{$record->phone_number}}</a> </div> <div class="flex mr-3"> <x-heroicon-o-mail class="h5 w-5 shrink-0 mr-2"/> <a href="mail:{{$record->email}}" class="text-primary-600">{{$record->email}}</a> </div> </div> <div class="lg:grid grid-cols-3 mt-5 gap-5"> <div> <div class="p-2 space-y-2 bg-white rounded-xl flex items-center justify-center shadow dark:border-gray-600 dark:bg-gray-800">` ` <div class="rounded-full border p-2"> <x-heroicon-o-download class="h-7"/> </div> <span style="margin-top:0;" class="p-0 pl-3 font-medium"> Scarica contratto </span> </div> <div class="p-2 space-y-2 bg-white rounded-xl mt-3 shadow dark:border-gray-600 dark:bg-gray-800"> @livewire("booking.details", ["record"=>$record]) </div> <div class="p-2 space-y-2 bg-white rounded-xl mt-3 shadow dark:border-gray-600 dark:bg-gray-800"> @livewire("booking.payments", ["record"=>$record]) </div> </div> <div> <div class="p-2 space-y-2 bg-white rounded-xl shadow dark:border-gray-600 dark:bg-gray-800"> @livewire("booking.history", ["record"=>$record]) </div> </div> <div> <div class="p-2 space-y-2 bg-white rounded-xl shadow dark:border-gray-600 dark:bg-gray-800"> <div> <div class="flex items-center justify-between gap-8 py-3"> <h2 class="text-lg font-semibold tracking-tight filament-card-heading"> Tickets </h2> {{$this->form}} </div> <div aria-hidden="true" class="filament-hr border-t dark:border-gray-700"></div> <div class="pt-2"> @livewire("booking.tickets", ["record"=>$record]) </div> </div> </div> </div> </div> </div> </x-filament::page>

Did you find this page helpful?