Laravel Filament v3.x:多选SelectFilter单选项移除功能问询
Laravel Filament v3: 解决多选SelectFilter指示器单值移除问题
原生支持情况
Filament v3原生的多选SelectFilter默认点击指示器的叉号会清空整个过滤器,这是因为默认指示器绑定的是过滤器的全局重置逻辑,而非单值移除。
解决方案:自定义指示器移除动作
通过Filament的Indicator组件和Livewire动作,我们可以实现点击单个指示器叉号仅移除对应值的功能,完全基于原生API实现,无需自定义前端代码。
直接修改过滤器代码
替换原有的indicateUsing方法,返回带自定义移除动作的Indicator实例数组:
use Filament\Support\Components\Indicator; use Filament\Tables\Actions\Action; Tables\Filters\SelectFilter::make('status') ->label('Order Status') ->multiple() ->options(OrderStatus::class) ->searchable() ->preload() ->indicateUsing(function (array $data): array { if (empty($data['values']) || !is_array($data['values'])) { return []; } return collect($data['values']) ->filter() ->map(function ($value) { // 获取状态标签,优先用枚举的getLabel方法 $label = OrderStatus::tryFrom($value)?->getLabel() ?? ucfirst($value); return Indicator::make($label) // 可选:根据状态设置指示器颜色 ->color(match ($value) { 'pending' => 'warning', 'completed' => 'success', 'cancelled' => 'danger', default => 'gray', }) ->removeAction( Action::make('remove') ->icon('heroicon-m-x-mark') ->size('sm') ->livewire() ->action(function (callable $set) use ($value) { // 获取当前选中的所有状态值 $currentValues = $set('tableFilters.status.values') ?? []; // 移除当前点击的状态值 $updatedValues = array_filter($currentValues, fn($v) => $v !== $value); // 更新过滤器选中值(重新索引数组避免空键) $set('tableFilters.status.values', array_values($updatedValues)); }) ); }) ->toArray(); }),
通用封装(可选)
如果需要在多个多选过滤器中复用该功能,可以封装成Trait:
// app/Filament/Traits/HasMultiSelectIndicatorRemoval.php namespace App\Filament\Traits; use Filament\Support\Components\Indicator; use Filament\Tables\Actions\Action; trait HasMultiSelectIndicatorRemoval { public function enableMultiSelectIndicatorRemoval(): static { return $this->indicateUsing(function (array $data): array { if (empty($data['values']) || !is_array($data['values'])) { return []; } // 获取过滤器的选项列表 $options = $this->getOptions(); return collect($data['values']) ->filter() ->map(function ($value) use ($options) { // 从选项中获取标签, fallback到首字母大写 $label = $options[$value] ?? ucfirst($value); return Indicator::make($label) ->removeAction( Action::make('remove') ->icon('heroicon-m-x-mark') ->size('sm') ->livewire() ->action(function (callable $set) use ($value) { $filterName = $this->getName(); // 获取当前过滤器的选中值 $currentValues = $set("tableFilters.{$filterName}.values") ?? []; // 移除目标值并重新索引 $updatedValues = array_filter($currentValues, fn($v) => $v !== $value); $set("tableFilters.{$filterName}.values", array_values($updatedValues)); }) ); }) ->toArray(); }); } }
使用时只需在过滤器上调用该方法:
use App\Filament\Traits\HasMultiSelectIndicatorRemoval; Tables\Filters\SelectFilter::make('status') ->label('Order Status') ->multiple() ->options(OrderStatus::class) ->searchable() ->preload() ->enableMultiSelectIndicatorRemoval(),
效果说明
完成修改后,点击单个状态指示器的叉号时,只会从过滤器的选中列表中移除对应状态,其他选中状态保持不变,符合预期的用户交互逻辑。
内容的提问来源于stack exchange,提问作者Rupesh Kayastha
相关产品推荐
相关产品推荐

