选择列
简介
选择列允许你在表格中渲染选择字段,用于更新该数据库记录,而无需打开新页面或模态框。
你必须向该列传入选项:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])

启用 JavaScript 选择器
默认情况下,Filament 使用原生 HTML5 select。你可以使用 native(false) 方法启用更可定制的 JavaScript 选择器:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->native(false)TIP
除静态值外,native() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。


搜索选项
你可以使用 searchableOptions() 方法启用搜索输入,以便更方便地访问大量选项:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->searchableOptions()可选地,你可以传入布尔值来控制输入是否可搜索:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->searchableOptions(FeatureFlag::active())TIP
除静态值外,searchableOptions() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
返回自定义搜索结果
如果选项很多,并希望基于数据库搜索或其他外部数据源填充,可以使用 getOptionsSearchResultsUsing() 和 getOptionLabelUsing() 方法,而不是 options()。
getOptionsSearchResultsUsing() 方法接受一个回调,以 $key => $value 格式返回搜索结果。当前用户的搜索词可通过 $search 获取,你应使用它来过滤结果。
getOptionLabelUsing() 方法接受一个回调,将所选选项的 $value 转换为标签。这在表单首次加载且用户尚未搜索时使用;否则将无法获取用于显示当前所选选项的标签。
若要提供自定义搜索结果,选择器上必须同时使用 getOptionsSearchResultsUsing() 和 getOptionLabelUsing():
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->searchableOptions()
->getOptionsSearchResultsUsing(fn (string $search): array => User::query()
->where('name', 'like', "%{$search}%")
->limit(50)
->pluck('name', 'id')
->all())
->getOptionLabelUsing(fn ($value): ?string => User::find($value)?->name),getOptionLabelUsing() 至关重要,因为它向 Filament 提供所选选项的标签,从而无需执行完整搜索即可找到。若选项无效,应返回 null。
TIP
你可以将各种工具作为参数注入到这些函数中。
设置自定义加载消息
使用可搜索的选择器或多选时,你可能希望在选项加载期间显示自定义消息。可使用 optionsLoadingMessage() 方法:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsLoadingMessage('Loading authors...')TIP
除静态值外,optionsLoadingMessage() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
设置自定义无搜索结果消息
使用可搜索的选择器或多选时,你可能希望在找不到搜索结果时显示自定义消息。可使用 noOptionsSearchResultsMessage() 方法:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->noOptionsSearchResultsMessage('No authors found.')TIP
除静态值外,noOptionsSearchResultsMessage() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
设置自定义搜索提示
使用可搜索的选择器或多选时,你可能希望在用户尚未输入搜索词时显示自定义消息。可使用 optionsSearchPrompt() 方法:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions(['name', 'email'])
->optionsSearchPrompt('Search authors by their name or email address')TIP
除静态值外,optionsSearchPrompt() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
设置自定义搜索中消息
使用可搜索的选择器或多选时,你可能希望在搜索结果加载期间显示自定义消息。可使用 optionsSearchingMessage() 方法:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsSearchingMessage('Searching authors...')TIP
除静态值外,optionsSearchingMessage() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
调整搜索防抖
默认情况下,当用户在可搜索的选择器或多选中输入时,Filament 会等待 1000 毫秒(1 秒)再搜索选项。若用户持续在搜索框中输入,两次搜索之间也会等待 1000 毫秒。你可以使用 optionsSearchDebounce() 方法更改此设置:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsSearchDebounce(500)请确保不要把防抖时间降得过低,否则可能因向服务器获取选项的网络请求过多,导致选择器变慢且无响应。
TIP
除静态值外,optionsSearchDebounce() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
与 Eloquent 关系集成
你可以使用 SelectColumn 的 optionsRelationship() 方法配置 BelongsTo 关系以自动获取选项。titleAttribute 是用于为每个选项生成标签的列名:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')跨多列搜索关系选项
默认情况下,若选择器也可搜索,Filament 会基于关系的标题列返回关系搜索结果。若希望跨多列搜索,可以向 searchableOptions() 方法传入列名数组:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions(['name', 'email'])预加载关系选项
若希望在页面加载时(而非用户搜索时)从数据库填充可搜索选项,可以使用 preloadOptions() 方法:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->preloadOptions()可选地,你可以传入布尔值来控制输入是否预加载:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->preloadOptions(FeatureFlag::active())TIP
除静态值外,preloadOptions() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
排除当前记录
处理递归关系时,你通常希望从结果集中移除当前记录。
这可通过 ignoreRecord 参数轻松完成:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('parent_id')
->optionsRelationship(name: 'parent', titleAttribute: 'name', ignoreRecord: true)自定义关系查询
你可以使用 optionsRelationship() 方法的第三个参数自定义检索选项的数据库查询:
use Filament\Tables\Columns\SelectColumn;
use Illuminate\Database\Eloquent\Builder;
SelectColumn::make('author_id')
->optionsRelationship(
name: 'author',
titleAttribute: 'name',
modifyQueryUsing: fn (Builder $query) => $query->withTrashed(),
)TIP
modifyQueryUsing 参数可以将各种工具作为参数注入到该函数中。
自定义关系选项标签
若希望自定义每个选项的标签(例如更描述性,或拼接名与姓),可以在数据库迁移中使用虚拟列:
$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'full_name')或者,你可以使用 getOptionLabelFromRecordUsing() 方法将选项的 Eloquent 模型转换为标签:
use Filament\Tables\Columns\SelectColumn;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
SelectColumn::make('author_id')
->optionsRelationship(
name: 'author',
modifyQueryUsing: fn (Builder $query) => $query->orderBy('first_name')->orderBy('last_name'),
)
->getOptionLabelFromRecordUsing(fn (Model $record) => "{$record->first_name} {$record->last_name}")
->searchableOptions(['first_name', 'last_name'])TIP
getOptionLabelFromRecordUsing() 方法可以将各种工具作为参数注入到该函数中。
记住选项
默认情况下,使用 optionsRelationship() 时,Filament 会在表格页面的生命周期内记住选项以提升性能。这意味着选项函数每个表格页面只会运行一次,而不是每个单元格运行一次。你可以使用 rememberOptions(false) 方法禁用此行为:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->rememberOptions(false)WARNING
记住选项时,任何针对特定记录的选项或禁用选项都无法正确工作,因为表格中所有记录都会使用同一组选项。若需要针对特定记录的选项或禁用选项,应禁用选项记忆。
TIP
除静态值外,rememberOptions() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
允许选项标签中的 HTML
默认情况下,Filament 会转义选项标签中的任何 HTML。若希望允许 HTML,可以使用 allowOptionsHtml() 方法:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('technology')
->options([
'tailwind' => '<span class="text-blue-500">Tailwind</span>',
'alpine' => '<span class="text-green-500">Alpine</span>',
'laravel' => '<span class="text-red-500">Laravel</span>',
'livewire' => '<span class="text-pink-500">Livewire</span>',
])
->searchableOptions()
->allowOptionsHtml()DANGER
请注意,你需要确保 HTML 可安全渲染,否则应用将面临 XSS 攻击风险。
可选地,你可以传入布尔值来控制输入是否允许 HTML:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('technology')
->options([
'tailwind' => '<span class="text-blue-500">Tailwind</span>',
'alpine' => '<span class="text-green-500">Alpine</span>',
'laravel' => '<span class="text-red-500">Laravel</span>',
'livewire' => '<span class="text-pink-500">Livewire</span>',
])
->searchableOptions()
->allowOptionsHtml(FeatureFlag::active())TIP
除静态值外,allowOptionsHtml() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
换行或截断选项标签
使用 JavaScript 选择器时,超出选择器元素宽度的标签默认会换行到多行。或者,你可以选择截断溢出的标签。
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('truncate')
->wrapOptionLabels(false)TIP
除静态值外,wrapOptionLabels() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
禁用占位符选择
你可以使用 selectablePlaceholder(false) 方法阻止选择占位符(null 选项):
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->selectablePlaceholder(false)TIP
除静态值外,selectablePlaceholder() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
禁用特定选项
你可以使用 disableOptionWhen() 方法禁用特定选项。它接受一个闭包,可在其中检查具有特定 $value 的选项是否应禁用:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->default('draft')
->disableOptionWhen(fn (string $value): bool => $value === 'published')TIP
你可以将各种工具作为参数注入到该函数中。
限制选项数量
你可以使用 optionsLimit() 方法限制可搜索选择器或多选中显示的选项数量。默认值为 50:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsLimit(20)请确保不要把限制提得过高,否则可能因浏览器内存占用过高,导致选择器变慢且无响应。
TIP
除静态值外,optionsLimit() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。
验证
你可以通过传入任意 Laravel 验证规则 数组来验证输入:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->rules(['required'])有效选项验证(in 规则)
in 规则确保用户无法选择不在选项列表中的选项。这对数据完整性很重要,因此 Filament 默认对所有选择字段应用该规则。
由于选择字段填充选项的方式很多,且许多情况下选项默认不会全部加载到选择器中、需要搜索才能获取,Filament 使用是否存在有效的「选项标签」来判断所选值是否存在。它还会检查该选项是否被禁用。
若使用自定义搜索查询检索选项,应确保定义了 getOptionLabelUsing() 方法,以便 Filament 能对照可用选项验证所选值:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->searchableOptions()
->getOptionsSearchResultsUsing(fn (string $search): array => Author::query()
->where('name', 'like', "%{$search}%")
->limit(50)
->pluck('name', 'id')
->all())
->getOptionLabelUsing(fn (string $value): ?string => Author::find($value)?->name),若选项无效,getOptionLabelUsing() 方法应返回 null,以便 Filament 判断所选值不在选项列表中。若选项有效,应返回该选项的标签。
若使用 optionsRelationship() 方法,getOptionLabelUsing() 方法会自动为你定义,因此无需担心。
生命周期钩子
可使用钩子在选择器生命周期的各个时刻执行代码:
SelectColumn::make()
->beforeStateUpdated(function ($record, $state) {
// Runs before the state is saved to the database.
})
->afterStateUpdated(function ($record, $state) {
// Runs after the state is saved to the database.
})安全性
授权
选择列在保存更改前不会自动检查 Laravel 模型策略(Model Policies)。当用户通过选择列更新值时,Filament 会检查该列是否 disabled(),但不会运行任何 update 策略门控检查。这意味着,只要用户能在表格中看到某条记录且该列未被禁用,即可更新该列的值,而不受你定义的任何 update 策略约束。若需限制谁可以编辑此列,应使用 disabled() 方法,根据你自己的授权逻辑有条件地阻止编辑,例如 disabled(fn ($record) => $record->user_id !== auth()->id())。或者,考虑使用完整的编辑页面或模态操作,在那里会强制执行 Filament 的资源授权。