You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 14:14:51