如何在Filament的Repeater组件中移除已选Select选项
实现Repeater中Select选项去重(排除已选Section)
要实现新增Repeater项时自动过滤已选的Section,核心是在section_id的Select组件中,动态获取当前Repeater所有已提交的Section ID并排除它们。以下是具体修改方案:
关键修改点
- 通过
Get助手获取整个Repeater的状态集合,提取已选的section_id - 查询Section时使用
whereNotIn排除已选ID,同时保留当前编辑项的ID(避免编辑现有条目时自身被过滤) - 优化
itemLabel的查询逻辑,提升性能
修改后的完整代码
Repeater::make('meal') ->relationship('meal') ->itemLabel(function (array $state): string{ // 优化查询:直接find替代where+get,更高效 return Section::find($state['section_id'])?->name ?? ''; }) ->schema([ Hidden::make('order_id')->default(1), Select::make('section_id') ->label('Section') ->searchable() ->options(function (Get $get) { // 获取当前Repeater所有已有的项 $repeaterItems = collect($get('../')); // 收集已选的Section ID,排除当前项的ID(编辑场景下保留自身) $existingSectionIds = $repeaterItems ->filter(fn($item) => isset($item['section_id'])) ->pluck('section_id') ->filter(fn($id) => $id !== $get('section_id')) ->toArray(); // 查询未被选中的Section return Section::query() ->when(!empty($existingSectionIds), fn($query) => $query->whereNotIn('id', $existingSectionIds)) ->pluck('name', 'id') ->toArray(); }) ->preload() ->required(), Select::make('product_id') ->label('Product') ->searchable() ->options(function (Get $get) { return Product::query() ->where('section_id', $get('section_id')) ->where('is_business', false) ->where('status', true) ->get() ->pluck('name', 'id') ->toArray(); }) ->preload() ->required(), ]) ->columns() ->minItems(1) ->maxItems(Section::all()->count()) ->cloneable() ->columnSpanFull() ->deleteAction( fn(Action $action) => $action->requiresConfirmation(), ) ->addActionLabel('Add New Meal'),
逻辑说明
- 获取Repeater状态:
$get('../')可以获取当前Repeater组件的所有项的状态集合,../表示向上遍历一层到Repeater本身 - 过滤已选ID:收集所有已存在的
section_id,同时排除当前项的ID(如果是编辑已有条目,不会把自己从选项中移除) - 动态查询选项:根据已选ID列表,用
whereNotIn过滤Section查询结果,确保新增项只能选择未被选中的Section
内容的提问来源于stack exchange,提问作者Hardik Kanajariya
相关产品推荐
相关产品推荐

