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

pieterdejong's avatar

Filament table method executed before listening method.

I'm using Filament, Livewire 3 and Laravel 11.

I stumbled upon a situation where the table method is being executed before my updateLocation method.

I added a dump to see the sequence and the result is 2, 1, 1, 1. I also don't understand why the updateLocation is executed 3 time but that is not the issue for this question.

Problem is, when is change my location on my other livewire component and dispatch $this->dispatch('update-location', location: $this->location); my table is not updated as expected because, table is updated before the new myLocation has been set.

I hope someone knows a different approach or has some tips on how to refresh the filament table. Already tried $this->dispatch('$refresh'); but did not work

My class looks like this:

<?php

namespace App\Livewire;

use App\EnumClasses\CountryCodes;
use App\Models\Place;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Tables\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Attributes\On;
use Livewire\Component;

class ListPlaces extends Component implements HasForms, HasTable
{
    use InteractsWithTable;
    use InteractsWithForms;

    /**
     * @var array|float[]
     */
    public array $myLocation;
    public $shouldRenderTable = false;

    public function mount(): void
    {
        $this->myLocation = [14.426422119140625, 50.06524954828362]; //longitude, latitude
    }

    public function updated(): void
    {
        $this->dispatch('update-place-filters', filterValues: $this->tableFilters);
    }

    #[On('update-location')]
    public function updateLocation(array $location): void
    {
        dump(1);
        $this->myLocation = $location;
    }

    public function table(Table $table): Table
    {
        $countryOptions = CountryCodes::COUNTRY_CODES;
        $countryOptions = array_flip($countryOptions);
        $countryOptions = $this->translateArray($countryOptions);
        dump(2);

        return $table
            ->query(Place::query()
                ->selectDistanceTo($this->myLocation)
                ->with('reviews')
            )

                ->modelLabel('Plaats')->pluralModelLabel('Plaatsen')
            ->columns([
                TextColumn::make('title')
                    ->extraAttributes(fn(Place $record): array => [
                        'onmouseenter' => sprintf('dispatch(\'highlight-marker-event\', { id: \'%s\', title: \'%s\' })', $record->id, $record->title),
                        'onmouseleave' => sprintf('dispatch(\'remove-highlight-marker-event\', {id: \'%s\'})', $record->id)
                    ])
                    ->label(__('place.Title'))
                    ->sortable(),
                TextColumn::make('distance')
                    ->label(__('place.Distance'))
                    ->formatStateUsing(fn (string $state): string => round($state / 1000, 2) . ' Km'),
                TextColumn::make('last_review')
                    ->name('created_at')
                    ->label(__('place.Last review'))
                    ->formatStateUsing(fn (Place $record): string => $record->reviews->last()?->created_at?->format('d-m-Y') ?? '' )
            ])
            ->filters([
                Filter::make('has_children_games')
                    ->label(__('place.Has children games'))
                    ->toggle()
                    ->query(fn (Builder $query): Builder => $query->where('has_children_games', true)),
                SelectFilter::make('country')
                    ->label(__('place.Country'))
                    ->multiple()
                    ->options($countryOptions)
                    ->attribute('country_iso'),
                Filter::make('max_price')
                    ->label(__('place.Max price'))
                    ->form([
                        TextInput::make('max_price'),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        return $query
                            ->when(
                                $data['max_price'] ?? '',
                                fn (Builder $query, $price): Builder => $query->where('parking_price', 'like', '%'.$price.'%'),
                            );
                    }),
                Filter::make('radius')
                    ->label(__('place.Radius'))
                    ->form([
                        TextInput::make('radius'),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        return $query
                            ->when(
                                $data['radius'] ?? '',
                                fn (Builder $query, $radius) : Builder => $query->withinDistanceTo($this->myLocation, $radius * 1000),
                            );
                    })

            ])
            ->filtersFormSchema(fn (array $filters): array => [
                Section::make(__('place.Location'))
                    ->schema([
                        $filters['country'],
                        $filters['radius']
                    ])->collapsed(),
                Section::make(__('place.Services'))
                    ->schema([
                        $filters['has_children_games'],
                    ])->collapsed(),
                Section::make(__('place.Terrain'))
                    ->schema([
                        $filters['max_price'],
                    ])
                    ->collapsed(true)
            ])->defaultSort('distance')
            ->actions([
                Action::make('show')
                    ->label(__('place.Details'))
                    ->button()
                    ->outlined()
                    ->action(fn(Place $record) => $record->advance())
                    ->modalContent(fn(Place $record): View => view(
                        'filament.place.detail',
                        ['place' => $record],
                    ))
                    ->modalSubmitAction(false)->modalCancelAction(false)


            ])
            ->bulkActions([
                // ...
            ]);
    }

    public function render(): View
    {
        return view('livewire.list-places');
    }
}
0 likes
4 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It seems like you're encountering an issue where the table method is being executed before your updateLocation method, which is causing the table not to be updated with the new location. To ensure that the table is updated after the location is changed, you can use Livewire's $refresh magic method to refresh the component, which should in turn call the table method again with the updated location.

Here's how you can modify your updateLocation method to refresh the component:

#[On('update-location')]
public function updateLocation(array $location): void
{
    dump(1);
    $this->myLocation = $location;
    $this->resetTable(); // Reset the table state
    $this->dispatchBrowserEvent('refresh-table'); // Dispatch a browser event to refresh the table
}

In your Livewire component's blade file, you can listen for the refresh-table event and call the $refresh magic method:

<div wire:init="table">
    {{-- Your table rendering code here --}}

    <script>
        document.addEventListener('refresh-table', () => {
            @this.call('$refresh');
        });
    </script>
</div>

This JavaScript snippet listens for the refresh-table event and calls the $refresh method on the Livewire component, which should cause the component to re-render and the table method to be called again with the updated myLocation.

Additionally, ensure that your other Livewire component that dispatches the update-location event is correctly emitting the event to the ListPlaces component. You can do this by using Livewire's emit method:

$this->emit('update-location', $this->location);

Make sure that the event name matches the one you're listening for in the ListPlaces component.

Lastly, regarding the updateLocation method being executed multiple times, this could be due to multiple instances of the component on the same page or multiple events being dispatched. You may want to investigate further to ensure that the event is only dispatched once and that there's only one instance of the component that needs to handle it.

1 like
ivanveraconvesio's avatar

I have not been able to find the solution I am trying to listen to an event sent from a filament table and to be able to render my component that has another filament table and to be able to update the information, but as much as I try it does not work, by the way I also have the same lifecycle first the table() function is executed as my listener class CollegeList extends Page implements HasForms { use AdvancedTables, InteractsWithForms, NotificationTrait, MyListTrait, CollegeTrait;

public $list;
public $list_id;

protected $listeners = ['showCollegeList'];

public function showCollegeList($list_id)
{
    dump(1);
    $user = Auth::user();
    $this->list_id = $list_id;
    $this->list = $this->getMyList($user->id, $list_id);

    /* 
    Here
    */
}

public function table(Table $table): Table
{
    dump(2);
    return $table
        ->query(CollegeListModel::query()->where('list_id', $this->list_id)/* ->with('colleges') */)
        ->columns([
            TextColumn::make('list_id')/* make('colleges.name')->label('Name') */,
        ])
        /*  ->recordUrl(
            fn (College $record) => dd($record)route('posts.edit', ['record' => $record->colleges->id] )
        )->openRecordUrlInNewTab(); */
        ->emptyStateHeading('No College Lists yet')
        ->emptyStateDescription('Once you create your first list, it will appear here.')
        ->emptyStateActions([
            Action::make('create')
                ->label('Add new list')
                ->icon('heroicon-m-plus')
                ->button()->action(function ($livewire, $record) {
                    $this->openModal();
                })
        ])->queryStringIdentifier('aa')->searchable();
}

public function render()
{
    dump(3);
    return view('livewire.insights.college-list');
}

}

vjupix's avatar

@ivanveraconvesio

Just saw this - so sorry for the delay. Did you try adding $this->resetTable() to your listener method?

So:

public function showCollegeList($list_id)
{
    dump(1);
    $user = Auth::user();
    $this->list_id = $list_id;
    $this->list = $this->getMyList($user->id, $list_id);

	$this->resetTable(); // <---- here!
}

Also did you make sure that the showCollegeList-method is called after you dispatched the event?

Please or to participate in this conversation.