Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Repeater field crashes when trying to reorder items #9

Open
PunchRockgroin opened this issue Jan 26, 2024 · 11 comments
Open

[Bug]: Repeater field crashes when trying to reorder items #9

PunchRockgroin opened this issue Jan 26, 2024 · 11 comments
Assignees
Labels
bug Something isn't working

Comments

@PunchRockgroin
Copy link

What happened?

I have a nested array which is reorderable, with data set up on a model using the HasSettingsField trait on an existing model. Using the Repeater field, the defaultSettings load normally, and save correctly. However, when trying to reorder the Repeater entries, I get:

Filament\Forms\ComponentContainer::getRawState(): Return value must be of type Illuminate\Contracts\Support\Arrayable|array, int returned

How to reproduce the bug

Using the following default settings on the model:

    public $defaultSettings = [
        'pre_event_stages' => [
            [
                'name' => 'Created',
                'slug' => 'created',
                'stageVersionNumber' => '01',
                'legacyFolderName' => '1_Master',
                'custom_difficulty_options' => []
            ],
            [
                'name' => 'Design',
                'slug' => 'design',
                'stageVersionNumber' => '02',
                'legacyFolderName' => '2_Design',
                'custom_difficulty_options' => []
            ],
            [
                'name' => 'Copy',
                'slug' => 'copy',
                'stageVersionNumber' => '03',
                'legacyFolderName' => '3_Copy',
                'custom_difficulty_options' => []
            ],
            [
                'name' => 'QA',
                'slug' => 'qa',
                'stageVersionNumber' => '04',
                'legacyFolderName' => '4_QA',
                'custom_difficulty_options' => [
                    [
                        'value' => 0,
                        'name' => 'Review',
                        'description' => 'We have clicked through your presentation and have made no edits.'
                    ],
                    [
                        'value' => 1,
                        'name' => 'Minor',
                        'description' => 'We have made minor edits to your presentation to ensure brand compliance.'
                    ],
                    [
                        'value' => 2,
                        'name' => 'Update',
                        'description' => 'We made minor edits to HPE slides for brand compliance and added the survey slide.'
                    ],
                    [
                        'value' => 3,
                        'name' => 'Revised',
                        'description' => 'We have made edits to your presentation to ensure brand compliance. For slides that we created revised graphics, we have kept your original slide in the back-up slides at the end of the presentation.'
                    ],
                ]
            ],
            [
                'name' => 'Ready to Upload',
                'slug' => 'ready-to-upload',
                'stageVersionNumber' => '05',
                'legacyFolderName' => '5_Ready to Upload',
                'custom_difficulty_options' => []
            ]
        ],
        'encounter_difficulty_options' => [
            [
                'value' => 0,
                'name' => 'Review',
                'description' => 'We have clicked through your presentation and have made no edits.'
            ],
            [
                'value' => 1,
                'name' => 'Minor',
                'description' => 'We have made minor edits to your presentation to ensure brand compliance.'
            ],
            [
                'value' => 2,
                'name' => 'Update',
                'description' => 'We made minor edits to HPE slides for brand compliance and added the survey slide.'
            ],
            [
                'value' => 3,
                'name' => 'Revised',
                'description' => 'We have made edits to your presentation to ensure brand compliance. For slides that we created revised graphics, we have kept your original slide in the back-up slides at the end of the presentation.'
            ],
        ],
    ];

Then, set the following on the model itself:

                            Repeater::make('settings.pre_event_stages')
//                                ->collapsed()
                                ->itemLabel(fn ($state): ?string => $state['name'] ?? null)
                                ->columns(2)
                                ->schema([
                                    TextInput::make('name')->required(),
                                    TextInput::make('slug')->required(),
                                    TextInput::make('stageVersionNumber')->required(),
                                    TextInput::make('legacyFolderName')->required(),
                                    Repeater::make('custom_difficulty_options')
                                        ->itemLabel(fn (array $state): ?string => $state['name'] ?? null)
//                                        ->collapsed()
                                        ->schema([
                                            TextInput::make('name')->required(),
                                            TextInput::make('value')
                                                ->numeric()
                                                ->inputMode('decimal')
                                                ->step(0.1)
                                                ->required(),
                                            TextInput::make('description')->required(),
                                        ])
                                        ->columnSpanFull()
                                        ->isModelSetting()
                                ])
                                ->isModelSetting()
                            ,
                            Repeater::make('settings.encounter_difficulty_options')
                                ->itemLabel(fn (array $state): ?string => $state['name'] ?? null)
//                                ->collapsed()
                                ->schema([
                                    TextInput::make('name')->required(),
                                    TextInput::make('value')
                                        ->numeric()
                                        ->inputMode('decimal')
                                        ->step(0.1)
                                        ->required(),
                                    TextInput::make('description')->required(),
                                ])
                                ->columns(2)
                                ->isModelSetting()
                        ]),

Saving works fine, however, re-ordering will trigger Filament\Forms\ComponentContainer::getRawState(): Return value must be of type Illuminate\Contracts\Support\Arrayable|array, int returned

The Repeater field works and re-orders when you remove 'isModelSetting()' from each repeater and when used as a standalone repeater field in it's own JSON database column, though without the 'defaults' being populated.

Package Version

1.1.0

PHP Version

8.2.1

Laravel Version

10.42.0

Which operating systems does with happen with?

No response

Notes

No response

@PunchRockgroin PunchRockgroin added the bug Something isn't working label Jan 26, 2024
Copy link
Contributor

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Feb 26, 2024
@Quadrubo Quadrubo self-assigned this Feb 27, 2024
@github-actions github-actions bot removed the stale label Feb 28, 2024
@Quadrubo
Copy link
Owner

Hey, sorry I took so long. I managed to take a look at this but wasn't able to reproduce this behaviour. Could you provide a more minimal example that also doesn't work for you? It would be best if you'd provide some kind of reproduction repo I can setup to have a look at.

@PunchRockgroin
Copy link
Author

No worries. I'm actually struggling to get it to work at all with a base Filament/Laravel 11 install. Not sure if this is a Laravel 11 issue, Herd or a SQLite issue, or if it's something else, but the $defaultSettings are not applying or being seen in Filament using the example color and can_add_students setup at https://github.com/Quadrubo/filament-model-settings?tab=readme-ov-file#settings-within-your-existing-resouce

I'll keep trying to get it to work and get back to you when I can.

@PunchRockgroin
Copy link
Author

I've got it working, and an example repo is here: https://github.com/PunchRockgroin/Filament-Model-Settings-Reorder-Issue

I've added a sqlite database at database/database.sqlite that's ready to go, with logins of test@test.com and secret and content added already.

Steps to reproduce:

  1. Log in
  2. Go to Hopper Events in sidebar
  3. Edit one that is already there, or create a new Hopper Event then edit.
  4. Try to reorder one of the repeaters in the Encounter Difficulty Options field
  5. You will get the error.
FilamentModelSettingReorderIssue.mp4

However, if you comment out isModelSetting() on the field and then change the cast to "array" as noted in https://filamentphp.com/docs/3.x/forms/fields/repeater#overview, and reorder, the error does not appear and the reorder can be saved.

I do note that glorand/laravel-model-settings#92 says not to cast as array, and this filamentphp/filament#8370 is the only other mention of the Filament\Forms\ComponentContainer::getRawState(): Return value must be of type Illuminate\Contracts\Support\Arrayable|array, int returned error message.

Let me know if you need any further information!

Copy link
Contributor

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Apr 28, 2024
@Quadrubo Quadrubo removed the stale label Apr 28, 2024
@zepfietje
Copy link

zepfietje commented May 7, 2024

Isn't this just a bug in Filament core? I'm running into the same thing.

Edit: my issue was caused by a custom addAction.

@Quadrubo
Copy link
Owner

Have tried debugging this a bit.
When retrieving the raw state in the function getRawState(). The data_get function tries to destructure the Livewire object.
In the livewire object, the options duplicated themselves with integer values which causes the return problem.

grafik

With a normal json repeater this doesn't happen.

grafik

I however have no idea what causes this.

@github-actions github-actions bot added the stale label Jun 13, 2024
@Quadrubo Quadrubo removed the stale label Jun 17, 2024
@github-actions github-actions bot added the stale label Jul 18, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Aug 1, 2024
@Quadrubo Quadrubo removed the stale label Aug 1, 2024
@Quadrubo Quadrubo reopened this Aug 1, 2024
@github-actions github-actions bot added the stale label Sep 1, 2024
Repository owner deleted a comment from github-actions bot Sep 3, 2024
Repository owner deleted a comment from github-actions bot Sep 3, 2024
Repository owner deleted a comment from github-actions bot Sep 3, 2024
Repository owner deleted a comment from github-actions bot Sep 3, 2024
@Quadrubo Quadrubo removed the stale label Sep 3, 2024
@github-actions github-actions bot added the stale label Oct 4, 2024
Repository owner deleted a comment from github-actions bot Oct 4, 2024
@Quadrubo Quadrubo removed the stale label Oct 4, 2024
@bergstar
Copy link

bergstar commented Nov 3, 2024

Is there any updates on this issue? Thank you for your attention to this matter

@peter-mw
Copy link

peter-mw commented Nov 5, 2024

I have the same issue

@AndriyVohar
Copy link

AndriyVohar commented Nov 15, 2024

You can create a custom form component (field) that extends the Repeater and overrides the getReorderAction() method to implement your desired behavior. Here's the revised function:

public function getReorderAction(): Action
{
    $action = Action::make($this->getReorderActionName())
        ->label(__('filament-forms::components.repeater.actions.reorder.label'))
        ->icon(FilamentIcon::resolve('forms::components.repeater.actions.reorder') ?? 'heroicon-m-arrows-up-down')
        ->color('gray')
        ->action(function (array $arguments, Repeater $component): void {
            $items = $component->getState();

            $reordered = array_map(fn($key) => $items[$key], $arguments['items']);

            $component->state(array_values($reordered));

            $component->callAfterStateUpdated();
        })
        ->livewireClickHandlerEnabled(false)
        ->iconButton()
        ->size(ActionSize::Small)
        ->visible(fn (Repeater $component): bool => $component->isReorderableWithDragAndDrop());

    if ($this->modifyReorderActionUsing) {
        $action = $this->evaluate($this->modifyReorderActionUsing, [
            'action' => $action,
        ]) ?? $action;
    }

    return $action;
}

Changes:

Original:

$items = [
    ...array_flip($arguments['items']),
    ...$component->getState(),
];

Updated:

$items = $component->getState();
$reordered = array_map(fn($key) => $items[$key], $arguments['items']);
$component->state(array_values($reordered));

Or you can use (string) Str::uuid() as the key of the array.

@PunchRockgroin
Copy link
Author

I've revisited this issue and used the custom Repeater component above (#9 (comment)).

I went in a different direction for my usage above, but this will come in handy in the future. Thanks @AndriyVohar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants