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

jcc5018's avatar

Filament v3 adding a livewire component

Ive posted a few times trying to put this data in the HobbyResource itself, but decided to try and make a dedicated livewire component to handle the hobbyRatings

Unfortunately, this is STILL not saving the results of the selected rating.

This was created via AI tools so i dont know if the syntax is uptodate for filament and livewire v3.

Or if i need to do anything else to have it save? I can get the fields to display, but i can't seem to store the selected value, and it is aggravating me.

Sample Data and View

<?php

namespace App\Livewire;

use App\Models\Hobby;
use App\Models\Tag;


use Illuminate\Database\Eloquent\Model;
use Livewire\Component;
use Illuminate\Contracts\View\View;

class Ratings extends Component
{
    public $hobby;
    public $ratings = [];

    public function mount(?Model $record): void
    {
        $this->hobby = $record;
        $this->loadRatings();
    }

    public function loadRatings()
    {
        $allRatings   = Tag::where('tag_type', 13)->get();
        $modelRatings = $this->hobby->hobbyRatings;

        foreach ($allRatings->where('parent_id', null) as $rating) {
            $options    = $allRatings->where('parent_id', $rating->id)
                                     ->pluck('tag', 'id')->toArray();
            $selectedId = $modelRatings->contains('id', $rating->id)
                ? $modelRatings->where('parent_id', $rating->id)->first()->id
                : null;

            $this->ratings[$rating->slug] = [
                'label'      => $rating->tag,
                'options'    => $options,
                'selectedId' => $selectedId,
            ];
        }
    }

    public function updatedRatings($ratingSlug, $value)
    {
        $this->updateHobbyRatings($ratingSlug, $value);
    }

    public function updateHobbyRatings($ratingSlug, $value)
    {
        if ($value) {
            $this->hobby->hobbyRatings()
                        ->syncWithoutDetaching([$value]); // Sync the selected ID
        } else {
            $id = array_search($ratingSlug, array_column($this->ratings,
                'slug')); // Retrieve ID based on slug
            $this->hobby->hobbyRatings()->detach($id); // Detach the ID
        }
    }

    public function render()
    {
        return view('livewire.ratings');
    }
}

Hobby Resource:

 Section::make('Ratings')
//                       ->relationship('hobbyRatings')
                       ->schema([
                        Livewire::make(Ratings::class),
                    ]),

Hobby Model

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

Blade

<div>
    @foreach ($ratings as $ratingSlug => $rating)
        <label for="rating_{{ $ratingSlug }}">{{ $rating['label'] }}</label>
        <x-filament::input.wrapper>
            <x-filament::input.select wire:model="ratings.{{ $ratingSlug }}.selectedId" id="rating_{{ $ratingSlug }}"
                                      wire:key="rating_{{ $ratingSlug }}">
                <option value="">Select rating</option>
                @foreach ($rating['options'] as $optionId => $optionLabel)
                    <option value="{{ $optionId }}">{{ $optionLabel }}</option>
                @endforeach
            </x-filament::input.select>
        </x-filament::input.wrapper>
    @endforeach
</div>
0 likes
4 replies
LaryAI's avatar
Level 58

It seems like you're trying to create a Livewire component that allows you to select ratings for a "Hobby" model and save them to the database. From the code you've provided, there are a few things to check and potentially correct to ensure that the selected values are saved properly.

First, ensure that your Livewire component is properly wired to your Blade template. The wire:model directive should be correctly bound to each select input. From your Blade code, it looks correct, but double-check that the ratings array structure in your Livewire component matches the structure you're expecting in the Blade view.

Second, in your updateHobbyRatings method, you're using syncWithoutDetaching to update the relationship. This method is used to sync many-to-many relationships without detaching the existing ones. However, if you want to update the rating for a specific "Hobby", you might want to use sync instead, as it will detach all other relationships not in the array passed to it. This assumes that each "Hobby" should only have one "Tag" of a specific type at a time.

Here's a revised version of the updateHobbyRatings method:

public function updateHobbyRatings($ratingSlug, $value)
{
    $tagId = array_key_exists($ratingSlug, $this->ratings) ? $this->ratings[$ratingSlug]['selectedId'] : null;

    if ($tagId) {
        // Sync the selected tag ID for the hobby
        $this->hobby->hobbyRatings()->sync([$tagId]);
    } else {
        // If no tag is selected, detach all tags of this type
        $this->hobby->hobbyRatings()->detach();
    }

    $this->hobby->load('hobbyRatings'); // Reload the relationship
}

Make sure to call $this->hobby->load('hobbyRatings'); after updating the relationship to refresh the loaded hobbyRatings relationship on the Hobby model.

Lastly, ensure that your Livewire component is included in the Filament resource correctly and that the mount method is receiving the correct Model instance. If the mount method is not being called with the expected Model instance, the component will not be able to load or save the ratings correctly.

If you've followed these steps and are still facing issues, please provide more details about the error or behavior you're encountering, and I'll be happy to help you further.

jcc5018's avatar

Does the added livewire component need its own submit button? I'd like to have it as part of the main hobby edit form

myregistration's avatar

@jcc5018 I assume you figured this out long ago, but in case anyone else happens across this post ...

Were you trying to update the record value when changing the select option? I just got stumped by this myself thinking the wire:model would automagically call the updated function, but then I realized you have to put .live or .change on wire:model because it's deferred by default (waiting for a submit). It used the be the opposite. So you would use wire:model.change for your select field if you want it to call the updated method when you select an option.

aurawindsurfing's avatar

AI writing the code and then replying to how to fix bugs in the code it wrote ;-)

1 like

Please or to participate in this conversation.