Desired Feature
Using a header button, the ‘company’ filter is toggled on and off with a custom option (“Google”).
Multiple Selection Filter Example
/*
Company filter is applied to the 'company' field on the Company model
Table function defined in the CompanyResource.php file as created by Filament
*/
namespace App\Filament\Resources;
public static function table(Table $table): Table
{
return $table
->headerActions([
Tables\Actions\Action::make('google_filter')
->badge()
->label('Google')
->icon(fn (ListRecords|TableWidget $livewire) => in_array(Companies::Google->value, Arr::get($livewire->tableFilters ?? [], 'company.values', []))
? 'heroicon-s-funnel'
: 'heroicon-o-funnel'
)
->action(fn (ListRecords|TableWidget $livewire) => self::buttonFilterApply($livewire, 'company', Companies::Google->value)),
Tables\Actions\Action::make('apple_filter')
->badge()
->label('Apple')
->icon(fn (ListRecords|TableWidget $livewire) => in_array(Companies::Apple->value, Arr::get($livewire->tableFilters ?? [], 'company.values', []))
? 'heroicon-s-funnel'
: 'heroicon-o-funnel'
)
->action(fn (ListRecords|TableWidget $livewire) => self::buttonFilterApply($livewire, 'company', Companies::Apple->value)),
])
->filters([
SelectFilter::make('company')
->multiple()
->native(false)
->options(Companies::class),
])
->columns([
TextColumn::make('name'),
TextColumn::make('job_title'),
TextColumn::make('location'),
TextColumn::make('company'),
]);
}
private static function buttonFilterApply(ListRecords|TableWidget $livewire, string $filter, string $option): void
{
$filter_value = (array) Arr::get($livewire->tableFilters ?? [], $filter, []);
if (empty($filter_value)) {
return;
}
if (in_array($option, $filter_value['values'])) {
$livewire->tableFilters[$filter]['values'] = array_diff($filter_value['values'], [$option]);
} else {
$livewire->tableFilters[$filter]['values'][] = $option;
}
}
Single Selection Filter Example
namespace App\Filament\Resources;
public static function table(Table $table): Table
{
return $table
->headerActions([
Tables\Actions\Action::make('google_filter')
->badge()
->label('Google')
->icon(fn (ListRecords|TableWidget $livewire) => Arr::get($livewire->tableFilters ?? [], 'company.value') === Companies::Google->value
? 'heroicon-s-funnel'
: 'heroicon-o-funnel'
)
->action(fn (ListRecords|TableWidget $livewire) => self::buttonFilterApply($livewire, 'company', Companies::Google->value)),
])
->filters([
SelectFilter::make('company')
->native(false)
->options(Companies::class),
])
->columns([
TextColumn::make('name'),
TextColumn::make('job_title'),
TextColumn::make('location'),
TextColumn::make('company'),
]);
}
private static function buttonFilterApply(ListRecords|TableWidget $livewire, string $filter, string $option): void
{
$filter_value = Arr::get($livewire->tableFilters ?? [], $filter);
if (empty($filter_value)) {
return;
}
$new_value = Arr::get($filter_value, 'value') === $option ? '' : $option;
$livewire->tableFilters[$filter] = ['value' => $new_value];
}
Support
Companies Enum
/*
Optional enum class for additional clarity above
*/
use Filament\Support\Contracts\HasLabel;
enum Companies: string implements HasLabel
{
case Google = 'Google';
case Apple = 'Apple';
case Yahoo = 'Yahoo';
public function getLabel(): ?string
{
return $this->name;
}
}
Livewire Type
In order for LaraStan to be happy, we need the correct livewire type applied to our icon()
& action()
methods on our header action - types that have the $tableFilters
property.
That Filament class is Filament\Resources\Pages\ListRecords
, however, in the event you utilize this table in a table widget you’ll need to union that
type with Filament\Widgets\TableWidget
, hence ListRecords|TableWidget $livewire
.