F
Filament•11mo ago
Damien

How do you implement create / edit actions correctly within custom widgets?

Hey everyone! I have been going around in circles a little bit with this and I think I am likely barking up the wrong tree but I have the following class
class RoomsOverview extends Widget implements HasActions, HasForms
{
use InteractsWithActions;
use InteractsWithForms;

protected static string $view = 'filament.resources.quote-resource.widgets.rooms-overview';

protected function getForms(): array
{
return [
'roomForm',
'floorConstructionForm',
];
}

public ?array $data = [];

public function mount(): void
{
$this->roomForm->fill();
$this->floorConstructionForm->fill();
}

public function roomForm(Form $form): Form {...}

public function floorConstructionForm(Form $form): Form {...}

public function createRoomAction(): Action {...}

public function editRoomAction(): Action {...}
}
class RoomsOverview extends Widget implements HasActions, HasForms
{
use InteractsWithActions;
use InteractsWithForms;

protected static string $view = 'filament.resources.quote-resource.widgets.rooms-overview';

protected function getForms(): array
{
return [
'roomForm',
'floorConstructionForm',
];
}

public ?array $data = [];

public function mount(): void
{
$this->roomForm->fill();
$this->floorConstructionForm->fill();
}

public function roomForm(Form $form): Form {...}

public function floorConstructionForm(Form $form): Form {...}

public function createRoomAction(): Action {...}

public function editRoomAction(): Action {...}
}
Creating a room, works as expected, however, I am struggling to get editing a room to work correctly and I feel like I am duplicating code unnecessarily across files. Here are some additional files for context.
// create|edit-room.blade.php
<div class="grid divide-x divide-gray-700 lg:grid-cols-12">
<div class="col-span-8 pr-4">{{ $this->roomForm }}</div>
<div class="col-span-4 pl-4">{{ $this->floorConstructionForm }}</div>
</div>
// create|edit-room.blade.php
<div class="grid divide-x divide-gray-700 lg:grid-cols-12">
<div class="col-span-8 pr-4">{{ $this->roomForm }}</div>
<div class="col-span-4 pl-4">{{ $this->floorConstructionForm }}</div>
</div>
I also have this snippet where I have the edit action on each room in a loop.
<div class="space-y-4 divide-y divide-dashed">
@if($rooms)
@foreach($rooms as $room)
<div class="pt-4 first:pt-0">
<div>
{{ $room->name }}
</div>
<div class="grid gap-5 grid-cols-12">

<div class="col-span-3 flex justify-end">{{ $this->editRoomAction() }}</div>

</div>
</div>
@endforeach
@endif
</div>
<div class="space-y-4 divide-y divide-dashed">
@if($rooms)
@foreach($rooms as $room)
<div class="pt-4 first:pt-0">
<div>
{{ $room->name }}
</div>
<div class="grid gap-5 grid-cols-12">

<div class="col-span-3 flex justify-end">{{ $this->editRoomAction() }}</div>

</div>
</div>
@endforeach
@endif
</div>
21 Replies
ConnorHowell
ConnorHowell•11mo ago
So what's the issue when you say editing isn't working? Is it not showing the current data? Are you getting an error? What are you expecting to happen and what is actually happening?
Damien
DamienOP•11mo ago
Hey Connor, i didn't expect you to hunt the thread down so that is greatly appreciated, I was just seeing if I could fix the issue before bumping it with a little refactoring. The issue I have that is when i click the edit button, the modal opens correctly but I cannot seem to populate it with the data for the record I am clicking edit on and I feel like I am missing something obvious despite going through the docs. Attached a couple images of the UI. When I click edit at the moment, every edit button loads too so I am not really sure what I have done wrong here 😅
No description
No description
Damien
DamienOP•11mo ago
happy to share / show any code snippets, never like spamming them until I know what is easiest
ConnorHowell
ConnorHowell•11mo ago
How's editRoomAction setup? That's where you should be filling the form data with the current record
Damien
DamienOP•11mo ago
Here is the setup for my edit action, the part I am having difficulty with is getting the record into the action.
public function editRoomAction(): Action
{
return Action::make('editRoom')
->label('Edit')
->modalHeading('Edit Room')
->modalContent(fn () => view('filament.resources.quote-resource.modals.edit-room'))
->modalFooterActionsAlignment(Alignment::End)
->modalWidth('5xl')
->action(function ($data, $arguments) {
dd($data, $arguments);
});
}
public function editRoomAction(): Action
{
return Action::make('editRoom')
->label('Edit')
->modalHeading('Edit Room')
->modalContent(fn () => view('filament.resources.quote-resource.modals.edit-room'))
->modalFooterActionsAlignment(Alignment::End)
->modalWidth('5xl')
->action(function ($data, $arguments) {
dd($data, $arguments);
});
}
This is mostly a duplicate of the create action as I haven't been able to figure out what to change in order to get it working correctly. (amended as I liked the incorrect one)
ConnorHowell
ConnorHowell•11mo ago
So in your modal you're rendering essentially just a split form? You should be able to achieve this then without a custom view by passing a form to the action itself? The other option I guess would be to make a custom livewire component that accepts the record as a parameter then pass that to the view in modalContent?
Damien
DamienOP•11mo ago
That's correct yes, the modal has 2 forms essentially. Let me see if I can change it so it works how you've said. Hmm, just rebuilding the form and looking to use use Filament\Forms\Components\Split; but it is saying this class isn't defined, it is in the version 3 docs too.
ConnorHowell
ConnorHowell•11mo ago
What version are you on? Believe split in forms was only added in 3.2
Damien
DamienOP•11mo ago
This could be it, I did then run sail php artisan filamnet:upgrade 3.1.9 Need to force it to use 3.2 it would seem?
ConnorHowell
ConnorHowell•11mo ago
Yeah update your composer.json to 3.2
Damien
DamienOP•11mo ago
So I can get everything into the form for the actions as you have suggested Connor (minus some styling) and I am using split for the 2 sections now. What is the best way to reuse a single form method within the 2 actions? As I am trying to not have to declare it for each action. Something like
return Action::make('createRoom')
->label('Create')
->modalHeading('New Room')
->form($this->form())
return Action::make('createRoom')
->label('Create')
->modalHeading('New Room')
->form($this->form())
but it is not happy about that
Damien
DamienOP•11mo ago
So here is a rough overview of it:
No description
Damien
DamienOP•11mo ago
clicking edit in the ui still gives me an empty modal so I assume I am missing something still? got the modal creating just fine so it is only the edit to fix which will be tomorrow now, thank you for your help so far.
ConnorHowell
ConnorHowell•11mo ago
You can use the fillForm method on the edit action then just pull in the associated record: https://filamentphp.com/docs/3.x/actions/modals#filling-the-form-with-existing-data
ConnorHowell
ConnorHowell•11mo ago
As for reusing the form I would just make a method called say “getRoomForm” and return the array and just call that in both. It’s just an array at the end of the day so wouldn’t need separating into a different class If you need to re-use these edit/create actions though I would suggest moving them into their own classes
Damien
DamienOP•11mo ago
Morning Connor, missed this yesterday so I will check this out this morning and see if I can get it working, I think I did try the fillform method but without luck. I will look again now this morning though. i am still failing to get the data to populate, here is the edit form fill form method:
->fillForm(fn (Room $room, RoomFloorConstructionItem $roomFloorConstructionItem) => [
'room-name' => $room->name,
'size' => $room->size,
'storey' => $room->storey,
'grouped-by' => $room->grouped_by,
'floor-finish' => $room->floor_finish,
'heating-product' => $room->heating_product,
'load-bearing-surface-product' => $room->load_bearing_surface_product,
'number-of-circuits' => $room->circuits_count,
'thermostat' => $room->thermostat,
'thimble-sensor' => $room->thimble_sensor,
'floor-sensor' => $room->floor_sensor,
'floor-items' => $roomFloorConstructionItem->toArray(),
])
->fillForm(fn (Room $room, RoomFloorConstructionItem $roomFloorConstructionItem) => [
'room-name' => $room->name,
'size' => $room->size,
'storey' => $room->storey,
'grouped-by' => $room->grouped_by,
'floor-finish' => $room->floor_finish,
'heating-product' => $room->heating_product,
'load-bearing-surface-product' => $room->load_bearing_surface_product,
'number-of-circuits' => $room->circuits_count,
'thermostat' => $room->thermostat,
'thimble-sensor' => $room->thimble_sensor,
'floor-sensor' => $room->floor_sensor,
'floor-items' => $roomFloorConstructionItem->toArray(),
])
I think, maybe some of the issue is that the form submits to 2 models, Rooms and RoomFloorConstructionItems - but I am likely wrong about this. Do I have to change the mount method also?
Damien
DamienOP•11mo ago
I think i tried this syntax but I will check it again now. So I have it setup like this right now:
<div class="hidden xl:flex xl:justify-end xl:col-start-11 xl:col-span-2">
{{ ($this->editRoomAction)(['data' => $room]) }}
</div>
<div class="hidden xl:flex xl:justify-end xl:col-start-11 xl:col-span-2">
{{ ($this->editRoomAction)(['data' => $room]) }}
</div>
->fillForm(function ($data) {
dd($data);
})
->fillForm(function ($data) {
dd($data);
})
This is what comes back: [] // app/Filament/Resources/QuoteResource/Widgets/RoomsOverview.php:316 Tried simplifying it to see if any data was being passed through but it appears not to be. The data is there though as I read it dynamically for the UI.
ConnorHowell
ConnorHowell•11mo ago
It's not passed back as $data in your action, if you do:
->fillForm(function (array $arguments) {
dd($arguments['data]);
})
->fillForm(function (array $arguments) {
dd($arguments['data]);
})
It should show you the data?
Damien
DamienOP•11mo ago
ah yes! the room data is now showing! (in the dd i might add) and it displays in UI too! I just need to get the floor construction items in there, which aren't displayed in the ui but I should be able to just fetch them based on the relationship and add them? ah it works! Thank you!
ConnorHowell
ConnorHowell•11mo ago
No worries!
Want results from more Discord servers?
Add your server