Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jcc5018's avatar

How do i manually save a generated field with filament

I posted this question a while ago, but Im still struggling to actually save the results using Filament

I want to create a series of select options (or radios/ checkboxes) that utilize my tags table to generate the choices. In this case it is hobbyRatings (tag type = 13).

This code below gets the individual ratings to display with their respective choices, but the choices are not saving, and I am not familiar enough with how the code works to know how to make it save, when everything else saves by default in filament.

See sample DB and expected rendering : Sample

The morph examples in the docs dont seem to align with this goal in mind, but I have many other needs for this solution, with the 60 tag_types (taxonomies) I have for various models. Adding the 'hobbyRating' in a ->relationship() doesnt support morphToMany, or if added within the loop, simply displays all rating parents and child options.

So again, the above code renders as expected but I'm not sure how to save it from there. Hope you can provide some guidance. Also, how do i see what data is being sent for troubleshooting?

Code: Hobby Model:

public function hobbyRatings(): MorphToMany
{
    return $this->morphToMany(Tag::class, 'taggable')->where('tag_type', 13)
                ->withTimestamps();
}

HOBBYRESOURCE

Section::make('Ratings')
                       ->schema(function (Hobby $record) {
                           $components   = [];
                           $allRatings   = Tag::type(13)->get();
                           $modelRatings = $record->hobbyRatings;

                           foreach (
                               $allRatings->where('parent_id', null) as $rating
                           ) {
                               $component = Select::make($rating->tag)
                                                  ->options($allRatings->where('parent_id',
                                                      $rating->id)->pluck('tag',
                                                      'id'));

                               if ($modelRatings->contains($rating->id)) {
                                   $component->default($modelRatings->where('parent_id',
                                       $rating->id)->first()->id);
                               }

                               $components[] = $component;
                           }

                           return $components;
                       })
0 likes
1 reply
LaryAI's avatar
Level 58

To save the selected values from the select options generated by your tags table in Filament, you need to ensure that the form handling logic is set up to handle the relationship saving. Since you're using a MorphToMany relationship, you'll need to handle the synchronization of the tags manually.

Here's a solution that includes the necessary steps to save the selected tags:

  1. Update your HobbyResource to include a saveRelationships method that will handle the synchronization of the tags.
  2. Ensure that the name of your Select components corresponds to the relationship method on your model.

Here's an example of how you might adjust your HobbyResource:

use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use App\Models\Hobby;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Section;

class HobbyResource extends Resource
{
    // ...

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Section::make('Ratings')
                    ->schema(function (Hobby $record) {
                        $components   = [];
                        $allRatings   = Tag::type(13)->get();
                        $modelRatings = $record->hobbyRatings;

                        foreach ($allRatings->where('parent_id', null) as $rating) {
                            $component = Select::make('hobbyRatings.' . $rating->id)
                                ->options($allRatings->where('parent_id', $rating->id)->pluck('tag', 'id'));

                            if ($modelRatings->contains('id', $rating->id)) {
                                $component->default($modelRatings->where('parent_id', $rating->id)->first()->id);
                            }

                            $components[] = $component;
                        }

                        return $components;
                    }),
                // ... other form components
            ]);
    }

    protected static function saveRelationships($record, $data): void
    {
        if (isset($data['hobbyRatings'])) {
            $tagIds = [];
            foreach ($data['hobbyRatings'] as $parentId => $childId) {
                if ($childId) {
                    $tagIds[] = $childId;
                }
            }
            $record->hobbyRatings()->sync($tagIds);
        }

        parent::saveRelationships($record, $data);
    }

    // ...
}

In this example, the Select::make component names are prefixed with hobbyRatings. followed by the ID of the parent rating. This is to ensure that each select field is uniquely named and can be properly associated with the corresponding tag.

The saveRelationships method is overridden to handle the synchronization of the tags. It checks if there's data for hobbyRatings, then loops through each of the select fields, collecting the selected tag IDs, and finally synchronizes the tags with the sync method.

To see what data is being sent for troubleshooting, you can use your browser's developer tools to inspect the network request when the form is submitted. Look for the form submission request and check the payload to see the data being sent to the server.

Please or to participate in this conversation.