F
Filament6mo ago
Dark

requiresConfirmation not working on actions

I have a Filament page where I have a list of actions (array)
public function logActivityModalActions(): array
{
$actions = [
Action::make('delete')
->label('Delete')
->color('danger')
->requiresConfirmation()
->action('deleteAction'),
];
}
public function logActivityModalActions(): array
{
$actions = [
Action::make('delete')
->label('Delete')
->color('danger')
->requiresConfirmation()
->action('deleteAction'),
];
}
And I am rendering this array like the following:
<x-filament-panels::form.actions
:actions="$this->actions"
/>
<x-filament-panels::form.actions
:actions="$this->actions"
/>
All is working well, but the requiresConfirmation() is not working the action is called without showing the confirmation dialog. any idea?
33 Replies
justlasse
justlasse6mo ago
If this is a custom view I think you’re missing the modals component to show the dialog.
Dark
Dark6mo ago
Oh I see, I will add it and check if it resolves the issue, thanks for you help I just try it but not working, here is my component:
// ...
use Filament\Pages\Page;
// ...

class Timesheet extends Page implements HasForms, HasActions
{
use InteractsWithActions;
use InteractsWithForms;

public function actions(): array
{
$actions = [
Action::make('delete')
->label('Delete')
->color('danger')
->requiresConfirmation()
->action('deleteAction'),
];
}

}
// ...
use Filament\Pages\Page;
// ...

class Timesheet extends Page implements HasForms, HasActions
{
use InteractsWithActions;
use InteractsWithForms;

public function actions(): array
{
$actions = [
Action::make('delete')
->label('Delete')
->color('danger')
->requiresConfirmation()
->action('deleteAction'),
];
}

}
and the blade view:
@foreach($this->actions() as $action)
{{ $action }}
@endforeach

<x-filament-actions::modals/>
@foreach($this->actions() as $action)
{{ $action }}
@endforeach

<x-filament-actions::modals/>
but still not working the HasForms and HasActions and the trait uses are already included in the Page (extended by the class) so it is not required, but added them or not does not change anything and just checked the x-filament-panel::page used in my class blade view I found that the <x-filament-actions::modals /> is already added
Dark
Dark6mo ago
because I have a modal containing some actions on the footer
Dark
Dark6mo ago
something like this
No description
Dark
Dark6mo ago
and the Delete button must show a confirmation I tought it was because the actions are showed inside a modal so there is a conflict or something, but I tested the actions outside the modals and the same issue
LeandroFerreira
LeandroFerreira6mo ago
share the whole code please
Dark
Dark6mo ago
@Leandro Ferreira yes of course here is the blade view
<x-filament-panels::page>

<div class="timesheet-container w-full flex flex-col relative z-10">

@include('filament-timesheet::livewire.partials.header')

@if($selectedView === 'board')
@include('filament-timesheet::livewire.partials.board')
@endif

@if($selectedView === 'timesheet')
@include('filament-timesheet::livewire.partials.timesheet')
@endif

</div>

<x-filament::modal id="filament-timesheet.log-activity-modal" width="lg" sticky-header sticky-footer>
<x-slot name="heading">
Log Activity
</x-slot>
<x-slot name="description">
Add work activity to your timesheet
</x-slot>
<x-filament-panels::form>
{{ $this->form }}

<x-filament-panels::form.actions
:actions="$this->logActivityModalActions()"
/>
</x-filament-panels::form>
</x-filament::modal>

<x-filament::modal id="filament-timesheet.duplicate-record-modal" width="lg" sticky-header sticky-footer>
<x-slot name="heading">
Duplicate Record
</x-slot>
<x-slot name="description">
Duplicate entry into your timesheet
</x-slot>
<x-filament-panels::form>
{{ $this->duplicationForm }}

<x-filament-panels::form.actions
:actions="$this->duplicationModalActions()"
/>
</x-filament-panels::form>
</x-filament::modal>

</x-filament-panels::page>
<x-filament-panels::page>

<div class="timesheet-container w-full flex flex-col relative z-10">

@include('filament-timesheet::livewire.partials.header')

@if($selectedView === 'board')
@include('filament-timesheet::livewire.partials.board')
@endif

@if($selectedView === 'timesheet')
@include('filament-timesheet::livewire.partials.timesheet')
@endif

</div>

<x-filament::modal id="filament-timesheet.log-activity-modal" width="lg" sticky-header sticky-footer>
<x-slot name="heading">
Log Activity
</x-slot>
<x-slot name="description">
Add work activity to your timesheet
</x-slot>
<x-filament-panels::form>
{{ $this->form }}

<x-filament-panels::form.actions
:actions="$this->logActivityModalActions()"
/>
</x-filament-panels::form>
</x-filament::modal>

<x-filament::modal id="filament-timesheet.duplicate-record-modal" width="lg" sticky-header sticky-footer>
<x-slot name="heading">
Duplicate Record
</x-slot>
<x-slot name="description">
Duplicate entry into your timesheet
</x-slot>
<x-filament-panels::form>
{{ $this->duplicationForm }}

<x-filament-panels::form.actions
:actions="$this->duplicationModalActions()"
/>
</x-filament-panels::form>
</x-filament::modal>

</x-filament-panels::page>
and the method used to retrieve the actions array
use Filament\Pages\Page;

class Timesheet extends Page
{
// ...
public function logActivityModalActions(): array
{
return [
Action::make('submitLogActivity')
->label('Save')
->action('submitLogActivity'),

Action::make('deleteLogActivity')
->label('Delete')
->color('danger')
->visible(fn() => $this->record['id'] != null)
->requiresConfirmation()
->action('deleteLogActivity'),
];
}
// ...
}
use Filament\Pages\Page;

class Timesheet extends Page
{
// ...
public function logActivityModalActions(): array
{
return [
Action::make('submitLogActivity')
->label('Save')
->action('submitLogActivity'),

Action::make('deleteLogActivity')
->label('Delete')
->color('danger')
->visible(fn() => $this->record['id'] != null)
->requiresConfirmation()
->action('deleteLogActivity'),
];
}
// ...
}
The class is much bigger, I remove the useless code
justlasse
justlasse6mo ago
Oh yeah modal inside modal is not supported. I had this issue as well and read something about it being to complex…
Daniel
Daniel6mo ago
i think this is only true for v2
justlasse
justlasse6mo ago
Could be but I have not had any success making it work 🙂 I’m all ears however
Daniel
Daniel6mo ago
i guess it muss be something else
Dark
Dark6mo ago
ow I see I am using Filament v3
justlasse
justlasse6mo ago
I couldn’t get it to work in v3 either, curious if anyone has some knowledge to share about it
Daniel
Daniel6mo ago
it seems only to work when action is a closure and not a string of a function which should be called
Action::make('deleteLogActivity')
->label('Delete')
->color('danger')
->visible(fn() => $this->record['id'] != null)
->requiresConfirmation()
->action(function () {
// do some stuff
}),
Action::make('deleteLogActivity')
->label('Delete')
->color('danger')
->visible(fn() => $this->record['id'] != null)
->requiresConfirmation()
->action(function () {
// do some stuff
}),
wagnerfnds
wagnerfnds6mo ago
already tried this way and also didnt work
justlasse
justlasse6mo ago
Yeah in my case it both ignores the confirmation and the action. I had to do a roundabout way for the action but still no go on the confirmation
Dark
Dark6mo ago
I found the solution, When using a function that defines an array of actions that did not work but when using a function that only defines a single Action it works So basically what it did work for me is to define a function for each Action that I have and follows the documentation here: https://filamentphp.com/docs/3.x/actions/adding-an-action-to-a-livewire-component/ And all works fine
justlasse
justlasse6mo ago
Would you mind sharing some snippets of your code?
Dark
Dark6mo ago
Yes sure, I will do it tonight when I have my laptop @justlasse here is for my case: - Not working example: In my Livewire Component I have a function that returns all my actions as an array:
public function myActions(): array {
return [
Action::make('delete')
->requiresConfirmation()
->action(fn () => /* some logic */),

// Other actions
];
}
public function myActions(): array {
return [
Action::make('delete')
->requiresConfirmation()
->action(fn () => /* some logic */),

// Other actions
];
}
Then in my blade view, I loop then render the action:
@foreach($this->myActions() as $action)
@if($action->isVisible())
{{ $action }}
@endif
@endforeach

<x-filament-actions::modals />
@foreach($this->myActions() as $action)
@if($action->isVisible())
{{ $action }}
@endif
@endforeach

<x-filament-actions::modals />
that works, but like there is no confirmation, it fires directly the action method. - Now, the working example:
public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action(fn () => /* some logic */)
;
}

public function myOtherAction(): Action {
return /* Action definition */
}
public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action(fn () => /* some logic */)
;
}

public function myOtherAction(): Action {
return /* Action definition */
}
And for the blade view, I render them separatly:
@if($myDeleteAction->isVisible())
{{ $myDeleteAction }}
@endif

@if($myOtherAction->isVisible())
{{ $myOtherAction }}
@endif

<x-filament-actions::modals />
@if($myDeleteAction->isVisible())
{{ $myDeleteAction }}
@endif

@if($myOtherAction->isVisible())
{{ $myOtherAction }}
@endif

<x-filament-actions::modals />
And also a weird behaviour I found, is when you define your Action with the following format, it WORKS:
public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action(fn () => /* some logic */) // The action is a function directly mentionned here
;
}
public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action(fn () => /* some logic */) // The action is a function directly mentionned here
;
}
But with the following format it does not WORK:
public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action('myDeleteActionHandler') // Mentionning the name of the handler
;
}

public function myDeleteActionHandler(): void {
/* some logic */
}
public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action('myDeleteActionHandler') // Mentionning the name of the handler
;
}

public function myDeleteActionHandler(): void {
/* some logic */
}
So basically, you need to specify a function for each action, then for the requiresConfirmation you need to specify the action as an embedded method in the action()
awcodes
awcodes6mo ago
myDeleteActionHandler is never registered as an action. Try ->action($this->myDeleteActionHandler())
justlasse
justlasse6mo ago
Thank you 🙏 It’s a bit strange what logic decides on this and how it works internally… I can’t find it in the code.
awcodes
awcodes6mo ago
Actions get cached, during registration (make) so when you try to call a string in the ->action() modifier it is trying to call a cached action by name. If you pass in a closure then it will just execute that closure.
justlasse
justlasse6mo ago
I get this when i try your working code
Call to undefined method Closure::isVisible()
Call to undefined method Closure::isVisible()
awcodes
awcodes6mo ago
Try just moving the function into ->action() directly. If you still have problems then the issue is somewhere in that function and not the action itself.
justlasse
justlasse6mo ago
I use an entryview in my infolist, and in the entryview i added the public function for the action, maybe that's the issue?
awcodes
awcodes6mo ago
Don’t know. I’d have to see more code.
justlasse
justlasse6mo ago
static function infolist(Infolist $infolist): Infolist
{
return $infolist
->name('story_infolist')
->schema([

Grid::make(1)->label('')->columnSpanFull()->schema([
// Actions::make([
// FilamentActionsAction::make('archive')
// ->icon('heroicon-o-archive-box')
// ->action(fn (Model $record) => $record->archive()),

// Action::make('restore')
// ->icon('heroicon-o-inbox')
// ->action(fn (Model $record) => $record->restore()),
// ]),
// ViewEntry::make('my_view')->view('infolists.components.stories.view.test'),
ViewActions::make('view_story_actions')
// ->view('infolists.components.stories.view.actions')
->label('')
->alignRight()
// ->columnSpanFull()
// ->hidden(fn (Model $record) => $record->completed)
]),
static function infolist(Infolist $infolist): Infolist
{
return $infolist
->name('story_infolist')
->schema([

Grid::make(1)->label('')->columnSpanFull()->schema([
// Actions::make([
// FilamentActionsAction::make('archive')
// ->icon('heroicon-o-archive-box')
// ->action(fn (Model $record) => $record->archive()),

// Action::make('restore')
// ->icon('heroicon-o-inbox')
// ->action(fn (Model $record) => $record->restore()),
// ]),
// ViewEntry::make('my_view')->view('infolists.components.stories.view.test'),
ViewActions::make('view_story_actions')
// ->view('infolists.components.stories.view.actions')
->label('')
->alignRight()
// ->columnSpanFull()
// ->hidden(fn (Model $record) => $record->completed)
]),
That's the part in my infolist for example
class Actions extends ViewEntry
{

public ?Model $record;
protected string $view = 'infolists.components.stories.view.actions';

public function markCompletedAction(): Action
{
return Action::make('markCompleted')
->requiresConfirmation()
->action(fn(Model $record) => $this->markCompleted($record))
;
}

public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action(fn (Story $story) => $this->markCompleted($story))
;
}

function markCompleted(Story $record) : void
{
dd('Here');
}
}
class Actions extends ViewEntry
{

public ?Model $record;
protected string $view = 'infolists.components.stories.view.actions';

public function markCompletedAction(): Action
{
return Action::make('markCompleted')
->requiresConfirmation()
->action(fn(Model $record) => $this->markCompleted($record))
;
}

public function myDeleteAction(): Action {
return Action::make('delete')
->requiresConfirmation()
->action(fn (Story $story) => $this->markCompleted($story))
;
}

function markCompleted(Story $record) : void
{
dd('Here');
}
}
Thats the actions "viewactions" class
<x-dynamic-component :component="$getEntryWrapperView()" :entry="$entry">
<div>
@if ($myDeleteAction()->isVisible())
{{ $myDeleteAction() }}
@endif
</div>
<x-filament-actions::modals />
</x-dynamic-component>
<x-dynamic-component :component="$getEntryWrapperView()" :entry="$entry">
<div>
@if ($myDeleteAction()->isVisible())
{{ $myDeleteAction() }}
@endif
</div>
<x-filament-actions::modals />
</x-dynamic-component>
Blade view Wait how did you get syntax coloring in the code??? As you can see i've experimented ALOT with these actions How do you add the action in your infolist? Do you add it directly in the schema or in a component?
Disouric
Disouric6mo ago
```php ```
justlasse
justlasse6mo ago
ohhhh Seems modals inside a modal infolist in a slideover just doesn't work... it works in the regualr infolist view but not when it's called in the slideover
justlasse
justlasse6mo ago
ViewEntry::make('my_view')
->alignRight()
->label('')
->registerActions([
Action::make('archive_test_1')->requiresConfirmation()->action(fn (Model $record, Complete $markComplete) => $markComplete->handle($record)),
Action::make('archive_test')
])
ViewEntry::make('my_view')
->alignRight()
->label('')
->registerActions([
Action::make('archive_test_1')->requiresConfirmation()->action(fn (Model $record, Complete $markComplete) => $markComplete->handle($record)),
Action::make('archive_test')
])