filament icon indicating copy to clipboard operation
filament copied to clipboard

Calling `callMountedFormComponentAction` with arguments does not pass the arguments

Open mansoorkhan96 opened this issue 1 year ago • 2 comments

Package

filament/filament

Package Version

v3.2

Laravel Version

v10.0

Livewire Version

v3.x

PHP Version

PHP8.2

Problem description

I have upgraded my Filament app from v3.0.62 to v3.2.x and I am facing following problem.

Problem:

I have added an Action to hintAction, It renders a custom Livewire component inside the action's modal. ->modalContent(fn ($record) => new HtmlString(Blade::render("@livewire('name-generator')")))

Inside the Livewire name-generator, i'm able to call $wire.$parent.callMountedFormComponentAction(@js(['name' => $name]))

And this calls the mountedAction as expected ->action(function (Set $set, $component, $arguments) However the injected $arguments is always an empty array.

The possible culprit

Seems like this is happening after this specific commit? https://github.com/filamentphp/filament/commit/a198bd1acea3d5c40ee564cf5d26055c6f23e59e

Expected behavior

By calling $wire.$parent.callMountedFormComponentAction() which calls the mountedAction ->action(function (Set $set, $component, $arguments), the $arguments variable should contain the arguments passed in callMountedFormComponentAction.

Which works in v3.0.62 but fails in new versions like v3.2.x.

Steps to reproduce

Lets say we want to generate a name using an API. We need to show a Modal which lists a few names that can be selected by clicking.

Skip reading steps by directly reviewing the Reproduction commit: https://github.com/mansoorkhan96/filament-playground/commit/87dc7eff24c50658cefc66b6cb7b23ba4e2d3720

Step 1

Add a Form Action to hintAction:

Forms\Components\TextInput::make('name')
    ->hintAction(
        Action::make('generate-name')
            ->modalSubmitAction(fn (StaticAction $action) => $action->hidden())
            ->modalContent(fn ($record) => new HtmlString(Blade::render("@livewire('name-generator')")))
            ->action(function (Set $set, $record, $arguments) {
                $set('name', $arguments['name']);
            })
    )

Step 2

Create NameGenerator Livewire component which should show the generated names list.

class NameGenerator extends Component
{
    public $aiGeneratedNames = [
        'John',
        'Jane',
        'Bob',
    ];

    public function render()
    {
        return view('livewire.name-generator');
    }
}

// blade file

<ul class="flex flex-col gap-2">
    @foreach ($aiGeneratedNames as $name)
        <li
            class="cursor-pointer"
            @click="$wire.$parent.callMountedFormComponentAction(@js(['name' => $name]))"
        >
            {{ $name }}
        </li>
    @endforeach
</ul>

Step 3

Now inside browser, clicking on the hint action generate-name should open a modal with the names list. Click on any name.

Actual behaviour

Clicking on name throws an ErrorException Undefined array key "name" which means the $arguments is empty and the $wire.$parent.callMountedFormComponentAction(@js(['name' => $name])) never passed the data.

Expected behaviour

Clicking on name should set name field to selected name without any Error/Exception.

Reproduction repository

https://github.com/mansoorkhan96/filament-playground

Relevant log output

No response

mansoorkhan96 avatar Feb 16 '24 18:02 mansoorkhan96

I tried to debug this and seems like the Action arguments are flushed out when following methods are called in HasFormComponentActions Trait:

getMountedFormComponentActionForm

// Line No: 57

$form = $this->getMountedFormComponentActionForm();

mountedFormComponentActionHasForm

// Line No: 62

if ($this->mountedFormComponentActionHasForm()) {
}

$action->mergeArguments($arguments); is called on Line: 55 and then after that, both of the above mentioned method calls flush out the arguments. If you dd($action->getArguments()) after any of the above method call, its an empty array. However, if you add the $action->mergeArguments($arguments); on Line: 69 again, It works and the arguments are successfully passed to ->action() method of the Action.

$action->mergeArguments($arguments); // here

$action->callBefore();

$result = $action->call([
    'form' => $form,
]);

mansoorkhan96 avatar Feb 18 '24 05:02 mansoorkhan96

@zepfietje @danharrin Should I send a PR to move down the $action->mergeArguments($arguments); and call it after the above mentioned methods? I am not quite sure if the arguments are also passed to LifecycleHook methods like: beforeFormValidated, afterFormValidated, before, etc.

mansoorkhan96 avatar Feb 18 '24 06:02 mansoorkhan96

Hey @danharrin Could you please help me what could be a work around for now.

Maybe some other way to handle this kind of requirement?

mansoorkhan96 avatar Mar 08 '24 12:03 mansoorkhan96

This was actually the next item on my Issues todo list, but each time the author @s me it kinda makes me not want to deal with it 😅 please be patient

danharrin avatar Mar 08 '24 12:03 danharrin

I apologise for not being patient. Thanks for taking time ❤️

mansoorkhan96 avatar Mar 08 '24 12:03 mansoorkhan96

Thank you so much for fixing this one.

mansoorkhan96 avatar Mar 11 '24 13:03 mansoorkhan96