F
Filamentโ€ข8mo ago
Saade

Bind $record in a custom action

Giving the following component:
// Component
class MyPage extends Component implements HasForms, HasActions
{
use InteractsWithForms;
use InteractsWithActions;

public function editAction(): Action
{
return Action::make('edit')
->mountUsing(function (Action $action, array $arguments): void {
// Resolve
$record = Author::find($arguments['id']);

// I'm guessing this, this will not work.
$action->record($record);
})
->form([
TextInput::make('title'),
Repeater::make('books')->relationship('books') // Repeater must know $record in order to work
])
->action(function (array $data, Model $record) {
$record->update($data);
})
}
}
// Component
class MyPage extends Component implements HasForms, HasActions
{
use InteractsWithForms;
use InteractsWithActions;

public function editAction(): Action
{
return Action::make('edit')
->mountUsing(function (Action $action, array $arguments): void {
// Resolve
$record = Author::find($arguments['id']);

// I'm guessing this, this will not work.
$action->record($record);
})
->form([
TextInput::make('title'),
Repeater::make('books')->relationship('books') // Repeater must know $record in order to work
])
->action(function (array $data, Model $record) {
$record->update($data);
})
}
}
<div>

Authors:

<span>Guilherme Saade {{ ($this->editAction)(['id' => 1]) }}</span>
<span>Dan Harrin {{ ($this->editAction)(['id' => 2]) }}</span>

<x-filament-actions:modals/>
</div>
<div>

Authors:

<span>Guilherme Saade {{ ($this->editAction)(['id' => 1]) }}</span>
<span>Dan Harrin {{ ($this->editAction)(['id' => 2]) }}</span>

<x-filament-actions:modals/>
</div>
How can i make the repeater know that the record is the $record resolved on mount? Made a little repro repo with everything set up, no need for migrations and seeders https://github.com/saade/filament-lab/tree/action-record
Solution:
Hey @Dan Harrin, is this something you could still work on? Or perhaps point me in the right direction. Thanks! I think https://discord.com/channels/883083792112300104/1176627389967646791/1176895501732413460 got implemented since when i've created this thread, the issue seems to be solved, thank you!...
Jump to solution
46 Replies
Lara Zeus
Lara Zeusโ€ข8mo ago
i usually use fillForm
Saade
Saadeโ€ข8mo ago
Yeah but i need the actual record in this case, because of the ->relationship() Made a little repro repo with everything set up, no need for migrations and seeders https://github.com/saade/filament-lab/tree/action-record
Dan Harrin
Dan Harrinโ€ข8mo ago
it would be nice if you could do ->record(fn ($arguments) => Author::find($arguments['id'])) not sure if thats possible, or how difficult it would be to implement
LeandroFerreira
LeandroFerreiraโ€ข8mo ago
maybe this?
->mountUsing(function (array $arguments, Form $form): void {
$record = User::find($arguments['id']);
$form->model($record);
$form->fill($record->attributesToArray());
})
->mountUsing(function (array $arguments, Form $form): void {
$record = User::find($arguments['id']);
$form->model($record);
$form->fill($record->attributesToArray());
})
Dan Harrin
Dan Harrinโ€ข8mo ago
it will only work on the first lw request when the modal opens
LeandroFerreira
LeandroFerreiraโ€ข8mo ago
hum..
Saade
Saadeโ€ข8mo ago
Hi Leandro, thanks for your response, the problem is exactly what Dan said so.. this is even possible?
Lara Zeus
Lara Zeusโ€ข8mo ago
this would help $arguments = Arr::last($livewire->mountedActionsArguments);
Dan Harrin
Dan Harrinโ€ข8mo ago
i think this would need to be the syntax its probably possible, yes does record() accept closures?
Lara Zeus
Lara Zeusโ€ข8mo ago
ummm, not sure I was using fillForm yup record(Model | Closure | null $record):
Saade
Saadeโ€ข8mo ago
yes, but the $arguments is not resolved there i think thats the problem and i dont know how to PR a "fix" for this
Dan Harrin
Dan Harrinโ€ข8mo ago
i wonder why track down where ->arguments() are set
Lara Zeus
Lara Zeusโ€ข8mo ago
->fillForm(function (Livewire $livewire) {
$arguments = Arr::last($livewire->mountedActionsArguments);

})
->fillForm(function (Livewire $livewire) {
$arguments = Arr::last($livewire->mountedActionsArguments);

})
Dan Harrin
Dan Harrinโ€ข8mo ago
it will not work after the first request, like adding a repeater item $arguments is available in fillForm() anyway
Saade
Saadeโ€ข8mo ago
the problem is not filling the form, its that the repeater does not know what $record to apply the relationship it tries to load the ->relationship() on null
Saade
Saadeโ€ข8mo ago
Resolving $arguments in ->record() is easy as adding it to the resolve function, but work only on first request
No description
Dan Harrin
Dan Harrinโ€ข8mo ago
1) arguments probably need to be passed in at the StaticAction level, or wherever the HasArguments trait is applied 2) after the first request, ->arguments() have to be passed back into the object, probably in getCachedAction() or something?
Saade
Saadeโ€ข8mo ago
1) arguments is properly resolved without my addition to the Action class, the problem is in the second request, my bad 2) that's a little bit beyond my knowledge, i can open an issue referencing this thread if that's ok to you
Dan Harrin
Dan Harrinโ€ข8mo ago
dont worry about the issue. i'll spend 10 minutes looking into it
Saade
Saadeโ€ข8mo ago
thank you Dan ๐Ÿ’› there's a repro repo in this thread, its all set up, including the database.sqlite
Dan Harrin
Dan Harrinโ€ข8mo ago
public function editAction(): Action
{
return EditAction::make()
->record(fn (array $arguments) => User::find($arguments['id']))
->form([
TextInput::make('name'),
Repeater::make('books')
->relationship('books')
->schema([
TextInput::make('title'),
]),
]);
}
public function editAction(): Action
{
return EditAction::make()
->record(fn (array $arguments) => User::find($arguments['id']))
->form([
TextInput::make('name'),
Repeater::make('books')
->relationship('books')
->schema([
TextInput::make('title'),
]),
]);
}
Saade
Saadeโ€ข8mo ago
let me try it yes! it works!! thank you let me try the fix in the adjacency-list plugin
Saade
Saadeโ€ข8mo ago
it works on the example i gave (using the actions packages on a lw compoennt), but i'm not sure this works while using inside a custom form component. do you see anything wrong here? https://github.com/saade/filament-adjacency-list/blob/feat/relationships/src/Forms/Components/Actions/EditAction.php#L58
Dan Harrin
Dan Harrinโ€ข8mo ago
the code i added before doesnt run for form component actions
Saade
Saadeโ€ข8mo ago
the $record i'm giving there is the right model, but the action thinks i'm refering to the form record (not the one i'm passing)
Dan Harrin
Dan Harrinโ€ข8mo ago
if you can make a super simple reproduction for form component actions i will look into it
Saade
Saadeโ€ข8mo ago
sure mate, thank you Hi mate, here's the repo with everything you need, just clone and run, database included. Go to the Authors edit page to read the problem description. https://github.com/saade/filament-lab/tree/action-record please use the action-record branch
Dan Harrin
Dan Harrinโ€ข8mo ago
btw i havent forgotten, just been super busy
Saade
Saadeโ€ข8mo ago
all good
Solution
Saade
Saadeโ€ข5mo ago
Hey @Dan Harrin, is this something you could still work on? Or perhaps point me in the right direction. Thanks! I think https://discord.com/channels/883083792112300104/1176627389967646791/1176895501732413460 got implemented since when i've created this thread, the issue seems to be solved, thank you!
LeandroFerreira
LeandroFerreiraโ€ข5mo ago
Hey, I think you can do this (remove ->relationship('chapters') in the AuthorResource)
$this->fillForm(
function (ListField $component, array $arguments): array {

$repeater = $component->getEditFormSchema()[1];
$repeater->model($this->getRecord());
$repeater->relationship('chapters');

return $component->getCachedExistingRecords()->firstWhere('id', $arguments['id'])->attributesToArray();
}
);
$this->fillForm(
function (ListField $component, array $arguments): array {

$repeater = $component->getEditFormSchema()[1];
$repeater->model($this->getRecord());
$repeater->relationship('chapters');

return $component->getCachedExistingRecords()->firstWhere('id', $arguments['id'])->attributesToArray();
}
);
Saade
Saadeโ€ข5mo ago
The problem is that $this->getRecord() resolves to the Author (resource) not the Book (relation of the author) even if its parent container (the adjacency list container) is bound to the correct model. Configuring an action with$action->record(Book), the repeater inside the form of the action should use the record from the action (Book), not from the resource (Author). Also, its a plugin so i can't simply hard-code that on the codebase, but thanks anyway.
LeandroFerreira
LeandroFerreiraโ€ข5mo ago
$repeater->model($this->getRecord()) Isn't $this->getRecord() resolving the Book model at this point? Also, its a plugin so i can't simply hard-code that on the codebase understood
Saade
Saadeโ€ข5mo ago
Nope, the User is resolved at this point the thing is that $action->record(Book) is doing nothing, the record is still the resource form record
LeandroFerreira
LeandroFerreiraโ€ข5mo ago
No description
No description
No description
Saade
Saadeโ€ข5mo ago
oh, $this->getRecord() yes this is the book record. but did you tried to "Add to chapters"?
LeandroFerreira
LeandroFerreiraโ€ข5mo ago
yes, I'm saving it manually
Saade
Saadeโ€ข5mo ago
No description
LeandroFerreira
LeandroFerreiraโ€ข5mo ago
take a look
LeandroFerreira
LeandroFerreiraโ€ข5mo ago
Saade
Saadeโ€ข5mo ago
what the actual fuck ๐Ÿคจ using only that?
LeandroFerreira
LeandroFerreiraโ€ข5mo ago
I'll send a PR
Saade
Saadeโ€ข5mo ago
cool, thanks!