F
Filament4mo ago
Damien

Can I change this edit / view behaviour or is it default?

Just following on from my initial question in https://discord.com/channels/883083792112300104/956270111176679516/1204000267918512200 - here is a little clip showing what is currently happening. What I prefer to happen, is that the modal just opens in my current view without first navigating to the resources table view.
44 Replies
Damien
Damien4mo ago
(just going to re-take the video to remove branding)
Damien
Damien4mo ago
developer
developer4mo ago
it's kinda similar to what I'm saying 😄 @Damien try to add the edit page to the resource so instead of getting a modal, you'll get a full-page edit form
public static function getPages(): array
{
return [
'index' => Pages\ListPosts::route('/'),
'view' => Pages\ViewPost::route('/{record}'),
'edit' => Pages\EditPost::route('/{record}/edit')
...
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListPosts::route('/'),
'view' => Pages\ViewPost::route('/{record}'),
'edit' => Pages\EditPost::route('/{record}/edit')
...
];
}
Damien
Damien4mo ago
My bad, maybe I didn't explain myself properly. I don't want a edit page, I want an edit modal but I want it to open from where the edit button is clicked and to not first navigate.
ConnorHowell
ConnorHowell4mo ago
How have you got the edit action setup? You can probably re-use the standard table edit action? You may need to give it the record though if it can't be inferred by however you've got the list view setup
Damien
Damien4mo ago
This is how I have it at the moment:
// ProjectResource
->actions([
Tables\Actions\EditAction::make()
->modalWidth('lg')
->modalFooterActionsAlignment('end'),
])
// ProjectResource
->actions([
Tables\Actions\EditAction::make()
->modalWidth('lg')
->modalFooterActionsAlignment('end'),
])
(searching for where I call it)
// latest-projects.blade.php
<x-filament::button tag="a" href="{{
\App\Filament\Resources\ProjectResource::getUrl(parameters: [
'tableAction' => \Filament\Tables\Actions\EditAction::getDefaultName(),
'tableActionRecord' => $project,
])
}}">
Edit
</x-filament::button>
// latest-projects.blade.php
<x-filament::button tag="a" href="{{
\App\Filament\Resources\ProjectResource::getUrl(parameters: [
'tableAction' => \Filament\Tables\Actions\EditAction::getDefaultName(),
'tableActionRecord' => $project,
])
}}">
Edit
</x-filament::button>
ConnorHowell
ConnorHowell4mo ago
Yeah so that's why it's redirecting you, that will give you the list views url and tell it to auto open the modal (same as if you clicked on the result in global search) You could potentially re-use the EditAction in your custom view and pass the current record with ->record()?
Damien
Damien4mo ago
Ah, so I got this from the docs I can give that a try, do you mean like, should I first turn it into a normal button with a click handler then?
ConnorHowell
ConnorHowell4mo ago
Yeah as if you were using a custom action anyway, but instead of that just use the original EditAction. Although I'm still not fully certain that would work if I'm honest Other option would be to just recreate the EditAction yourself, you don't need to re-create the form as you can just do ProjectResource::form()
developer
developer4mo ago
hey @ConnorHowell ain't a better solution to make a call to the edit page of the resource from custom action at any other places is that even possible?
ConnorHowell
ConnorHowell4mo ago
Yeah if you want to use a separate edit page, but there is no 'edit page' in this scenario
developer
developer4mo ago
but how?
ConnorHowell
ConnorHowell4mo ago
If you don't have a seperate edit page it'll open in a modal
Damien
Damien4mo ago
I will look into this.
ConnorHowell
ConnorHowell4mo ago
@Damien Take a look at: https://github.com/filamentphp/filament/blob/d59842c84e4439c2c421ed7a06266c61bb33730a/packages/tables/src/Actions/EditAction.php#L13 And https://github.com/filamentphp/filament/blob/d59842c84e4439c2c421ed7a06266c61bb33730a/packages/panels/src/Resources/Pages/ListRecords.php#L147 This is how it works on the ListRecords/index page The reason why it needs to redirect you currently is because you have no edit action on your custom page
Damien
Damien4mo ago
awesome, thanks.
developer
developer4mo ago
@ConnorHowell is there a way to load the edit page in a modal? something like this using the ->modalContent() method:
// lets set a custom action any page
Tables\Actions\Action::make('New edit button')
->modalContent( fn () => \Pages\EditPost::render() )
->slideOver(),
// lets set a custom action any page
Tables\Actions\Action::make('New edit button')
->modalContent( fn () => \Pages\EditPost::render() )
->slideOver(),
*not working
ConnorHowell
ConnorHowell4mo ago
Nah I also feel that'd probably be terrible, you can use forms in an action anyway that shows in a modal. Take a look at the 2 links I put above to see how it works in core at the moment
developer
developer4mo ago
ok
Dan Harrin
Dan Harrin4mo ago
you are currently telling filament to insert an <a> tag to take the user to the table hence why filament is taking the user to the table if you want the modal to open from the curent component, you must define the action
Damien
Damien4mo ago
reading through that page now.
developer
developer4mo ago
you can add an action to a Livewire component, but can you trigger a LW component from an action?
Dan Harrin
Dan Harrin4mo ago
wdym trigger a livewire component
developer
developer4mo ago
somthing like this:
// lets set a custom action any page
Tables\Actions\Action::make('New edit button')
->livewire( fn () => \Pages\EditPost )
->slideOver(),
// lets set a custom action any page
Tables\Actions\Action::make('New edit button')
->livewire( fn () => \Pages\EditPost )
->slideOver(),
a Page is just a livewire component right?
Dan Harrin
Dan Harrin4mo ago
i dont get it a page is a page, with a sidebar and everything an action can contain a form we even have EditAction that saves it for you
developer
developer4mo ago
yeah. but in case we need to trigger a page from a different resource (while I'm thinking a page is just a LW component)
Dan Harrin
Dan Harrin4mo ago
a page is a livewire component, but all it does is read the form from a resource and renders it with a sidebar and stuff
developer
developer4mo ago
I know, Im kinda lost
Dan Harrin
Dan Harrin4mo ago
yea
ConnorHowell
ConnorHowell4mo ago
The main part of an edit page is a form, you can render a form in a modal already and you can even just call the static method on the resource
Dan Harrin
Dan Harrin4mo ago
EditAction::make()
->form(fn ($form) => ResourceName::form($form))
->slideOver()
EditAction::make()
->form(fn ($form) => ResourceName::form($form))
->slideOver()
this will open the resource form in a slideover
developer
developer4mo ago
awesome
Dan Harrin
Dan Harrin4mo ago
this is the exact code that is used when you have a simple resource
developer
developer4mo ago
lemme try it asap
Damien
Damien4mo ago
I've created a livewire component and defined the action, but when I click edit, it says edit is not a method on the model, which is correct because I haven't created it there. I have
// latest-projects.blade.php
@foreach($this->data['projects'] as $project)
@livewire('latest-project', ['project' => $project])
@endforeach
// latest-projects.blade.php
@foreach($this->data['projects'] as $project)
@livewire('latest-project', ['project' => $project])
@endforeach
// latest-project.blade.php
<div>
{{ ($this->editAction)(['project' => $project]) }}

<x-filament-actions::modals/>
</div>
// latest-project.blade.php
<div>
{{ ($this->editAction)(['project' => $project]) }}

<x-filament-actions::modals/>
</div>
// LatestProject.php
<?php

namespace App\Livewire;

use App\Models\Project;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;

class LatestProject extends Component implements HasActions, HasForms
{
use InteractsWithActions;
use InteractsWithForms;

public Project $project;

public function editAction(): Action
{
return Action::make('edit')
->action(fn () => $this->project->edit()); // Call to undefined method App\Models\Project::edit()
}

public function render()
{
return view('livewire.latest-project');
}
}
// LatestProject.php
<?php

namespace App\Livewire;

use App\Models\Project;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;

class LatestProject extends Component implements HasActions, HasForms
{
use InteractsWithActions;
use InteractsWithForms;

public Project $project;

public function editAction(): Action
{
return Action::make('edit')
->action(fn () => $this->project->edit()); // Call to undefined method App\Models\Project::edit()
}

public function render()
{
return view('livewire.latest-project');
}
}
Which everything seems to look okay when following the docs you linked Dan. PS. Naming is hideous as the minute but I can refactor that once working. So do I need an edit method on the model that uses the ProjectResource?
Dan Harrin
Dan Harrin4mo ago
where did you get $this->project->edit() from
EditAction::make()
->record($this->project)
->form(fn ($form) => ProjectResource::form($form));
EditAction::make()
->record($this->project)
->form(fn ($form) => ProjectResource::form($form));
Damien
Damien4mo ago
I took the example in the docs and changed it to edit 😅
public function deleteAction(): Action
{
return Action::make('delete')
->requiresConfirmation()
->action(fn () => $this->post->delete());
}
public function deleteAction(): Action
{
return Action::make('delete')
->requiresConfirmation()
->action(fn () => $this->post->delete());
}
Dan Harrin
Dan Harrin4mo ago
delete is an actual method on an eloquent model that deletes the model this isnt as magic as you think it is
Damien
Damien4mo ago
You are magic Dan!
Dan Harrin
Dan Harrin4mo ago
to recreate it, its something like this
Action::make('edit')
->fillForm($this->post->attributesToArray())
->form([TextInput::make('fdsfdf').....])
->action(fn ($data) => $this->post->update($data))
Action::make('edit')
->fillForm($this->post->attributesToArray())
->form([TextInput::make('fdsfdf').....])
->action(fn ($data) => $this->post->update($data))
thats basically all its doing but my previous code example is more succinct i encourage you to read through the entire Modals docs page to see the possibilities
Damien
Damien4mo ago
Roger, thank you, and it is working. Believe it or not, I spend a lot of time going through the docs but sadly I sometimes struggle to digest information sometimes and I have found the change from React world to Laravel quite a difference to be had! Super appreciate the support and help though and for the most part, I do get what I need from the docs.
developer
developer4mo ago
hey thank you Dan, its working fine for me 💪