Quite often in Filament we need to add widgets with stats above the table. In this lesson, let's see how to auto-update those stats in the widget when the filter is set in the table.
DB Structure
We will have an Order
Eloquent Model with an OrderResource
Filament Resource for this simple example.
database/migrations/xxx_create_orders_table.php:
public function up(): void{ Schema::create('orders', function (Blueprint $table) { $table->id(); $table->string('number'); $table->string('status'); $table->timestamps(); });}
Filament Table with Filter
We need to show a table with a custom filter for Filament Resource.
app/Filament/OrderResource.php:
use Illuminate\Support\Carbon;use Illuminate\Database\Eloquent\Builder; class OrderResource extends Resource{ // ... public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('number'), Tables\Columns\TextColumn::make('status'), ]) ->filters([ Tables\Filters\Filter::make('created_at') ->form([ Forms\Components\DatePicker::make('created_from') ->placeholder(fn ($state): string => 'Dec 18, ' . now()->subYear()->format('Y')), Forms\Components\DatePicker::make('created_until') ->placeholder(fn ($state): string => now()->format('M d, Y')), ]) ->query(function (Builder $query, array $data): Builder { return $query ->when( $data['created_from'] ?? null, fn (Builder $query, $date): Builder => $query->whereDate('created_at', '>=', $date), ) ->when( $data['created_until'] ?? null, fn (Builder $query, $date): Builder => $query->whereDate('created_at', '<=', $date), ); }) ->indicateUsing(function (array $data): array { $indicators = []; if ($data['created_from'] ?? null) { $indicators['created_from'] = 'Order from ' . Carbon::parse($data['created_from'])->toFormattedDateString(); } if ($data['created_until'] ?? null) { $indicators['created_until'] = 'Order until ' . Carbon::parse($data['created_until'])->toFormattedDateString(); } return $indicators; }), ]) ->actions([ Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } // ...}
Stats Widget Above the Table
And finally, let's add a stats overview widget. We will show the total number of orders and the number of orders based on the status.
app/Filament/Resources/OrderResource/Widgets/OrderStats.php:
use App\Models\Order;use Filament\Widgets\StatsOverviewWidget;use Filament\Widgets\StatsOverviewWidget\Stat; class OrderStats extends StatsOverviewWidget{ protected static ?string $pollingInterval = null; protected function getStats(): array { return [ Stat::make('Total orders', Order::count()), Stat::make('Confirmed Orders', Order::where('status', 'confirmed')->count()), Stat::make('Cancelled Orders', Order::where('status', 'cancelled')->count()), ]; }}
Applying Table Query to Widgets
To update widgets data according to the tables query, we can use a method getPageTableQuery()
. But to use this method, first, we must prepare widgets and list records classes.
We must add an ExposesTableToWidgets
trait to the ListOrders
class.
app/Filament/Resources/OrderResource/Pages/ListOrders.php:
use Filament\Pages\Concerns\ExposesTableToWidgets; class ListOrders extends ListRecords{ use ExposesTableToWidgets; // ...}
For the widget class, we must add an InteractsWithPageTable
trait and add the getTablePage()
method to specify the list's class. In our case, it is ListOrders
.
app/Filament/Resources/OrderResource/Widgets/OrderStats.php:
use Filament\Widgets\Concerns\InteractsWithPageTable;use App\Filament\Resources\OrderResource\Pages\ListOrders; class OrderStats extends StatsOverviewWidget{ use InteractsWithPageTable; protected function getTablePage(): string { return ListOrders::class; } // ...}
Instead of starting an Eloquent query with a Model, we can change that to $this->getPageTableQuery()
.
app/Filament/Resources/OrderResource/Widgets/OrderStats.php:
class OrderStats extends StatsOverviewWidget{ // ... protected function getStats(): array { return [ Stat::make('Total orders', Order::count()), Stat::make('Confirmed Orders', Order::where('status', 'confirmed')->count()), Stat::make('Cancelled Orders', Order::where('status', 'cancelled')->count()), Stat::make('Total orders', $this->getPageTableQuery()->count()), Stat::make('Confirmed Orders', $this->getPageTableQuery()->where('status', 'confirmed')->count()), Stat::make('Cancelled Orders', $this->getPageTableQuery()->where('status', 'cancelled')->count()), ]; }}
And that's it. Now, the base query will be taken from the table, and we can add the necessary conditions.
You can find the code in the GitHub repository.
If you want more Filament examples, you can find more real-life projects on our FilamentExamples.com.
No comments or questions yet...