Skip to content
全部文档

选择列

简介

选择列允许你在表格中渲染选择字段,用于更新该数据库记录,而无需打开新页面或模态框。

你必须向该列传入选项:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('status')
    ->options([
        'draft' => 'Draft',
        'reviewing' => 'Reviewing',
        'published' => 'Published',
    ])
选择列选择列

启用 JavaScript 选择器

默认情况下,Filament 使用原生 HTML5 select。你可以使用 native(false) 方法启用更可定制的 JavaScript 选择器:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('status')
    ->options([
        'draft' => 'Draft',
        'reviewing' => 'Reviewing',
        'published' => 'Published',
    ])
    ->native(false)

TIP

除静态值外,native() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

带 JavaScript 选择列的表格带 JavaScript 选择列的表格

搜索选项

你可以使用 searchableOptions() 方法启用搜索输入,以便更方便地访问大量选项:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->label('Author')
    ->options(User::query()->pluck('name', 'id'))
    ->searchableOptions()

可选地,你可以传入布尔值来控制输入是否可搜索:

php
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()

php
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() 方法:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->searchableOptions()
    ->optionsLoadingMessage('Loading authors...')

TIP

除静态值外,optionsLoadingMessage() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

设置自定义无搜索结果消息

使用可搜索的选择器或多选时,你可能希望在找不到搜索结果时显示自定义消息。可使用 noOptionsSearchResultsMessage() 方法:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->searchableOptions()
    ->noOptionsSearchResultsMessage('No authors found.')

TIP

除静态值外,noOptionsSearchResultsMessage() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

设置自定义搜索提示

使用可搜索的选择器或多选时,你可能希望在用户尚未输入搜索词时显示自定义消息。可使用 optionsSearchPrompt() 方法:

php
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() 方法:

php
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() 方法更改此设置:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->searchableOptions()
    ->optionsSearchDebounce(500)

请确保不要把防抖时间降得过低,否则可能因向服务器获取选项的网络请求过多,导致选择器变慢且无响应。

TIP

除静态值外,optionsSearchDebounce() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

与 Eloquent 关系集成

你可以使用 SelectColumnoptionsRelationship() 方法配置 BelongsTo 关系以自动获取选项。titleAttribute 是用于为每个选项生成标签的列名:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')

跨多列搜索关系选项

默认情况下,若选择器也可搜索,Filament 会基于关系的标题列返回关系搜索结果。若希望跨多列搜索,可以向 searchableOptions() 方法传入列名数组:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->searchableOptions(['name', 'email'])

预加载关系选项

若希望在页面加载时(而非用户搜索时)从数据库填充可搜索选项,可以使用 preloadOptions() 方法:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->searchableOptions()
    ->preloadOptions()

可选地,你可以传入布尔值来控制输入是否预加载:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->searchableOptions()
    ->preloadOptions(FeatureFlag::active())

TIP

除静态值外,preloadOptions() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

排除当前记录

处理递归关系时,你通常希望从结果集中移除当前记录。

这可通过 ignoreRecord 参数轻松完成:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('parent_id')
    ->optionsRelationship(name: 'parent', titleAttribute: 'name', ignoreRecord: true)

自定义关系查询

你可以使用 optionsRelationship() 方法的第三个参数自定义检索选项的数据库查询:

php
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 参数可以将各种工具作为参数注入到该函数中。

自定义关系选项标签

若希望自定义每个选项的标签(例如更描述性,或拼接名与姓),可以在数据库迁移中使用虚拟列:

php
$table->string('full_name')->virtualAs('concat(first_name, \' \', last_name)');
php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'full_name')

或者,你可以使用 getOptionLabelFromRecordUsing() 方法将选项的 Eloquent 模型转换为标签:

php
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) 方法禁用此行为:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->rememberOptions(false)

WARNING

记住选项时,任何针对特定记录的选项或禁用选项都无法正确工作,因为表格中所有记录都会使用同一组选项。若需要针对特定记录的选项或禁用选项,应禁用选项记忆。

TIP

除静态值外,rememberOptions() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

允许选项标签中的 HTML

默认情况下,Filament 会转义选项标签中的任何 HTML。若希望允许 HTML,可以使用 allowOptionsHtml() 方法:

php
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:

php
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 选择器时,超出选择器元素宽度的标签默认会换行到多行。或者,你可以选择截断溢出的标签。

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('truncate')
    ->wrapOptionLabels(false)

TIP

除静态值外,wrapOptionLabels() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

禁用占位符选择

你可以使用 selectablePlaceholder(false) 方法阻止选择占位符(null 选项):

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('status')
    ->options([
        'draft' => 'Draft',
        'reviewing' => 'Reviewing',
        'published' => 'Published',
    ])
    ->selectablePlaceholder(false)

TIP

除静态值外,selectablePlaceholder() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

禁用特定选项

你可以使用 disableOptionWhen() 方法禁用特定选项。它接受一个闭包,可在其中检查具有特定 $value 的选项是否应禁用:

php
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:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('author_id')
    ->optionsRelationship(name: 'author', titleAttribute: 'name')
    ->searchableOptions()
    ->optionsLimit(20)

请确保不要把限制提得过高,否则可能因浏览器内存占用过高,导致选择器变慢且无响应。

TIP

除静态值外,optionsLimit() 方法也接受函数以动态计算该值。你可以将各种工具作为参数注入到函数中。

验证

你可以通过传入任意 Laravel 验证规则 数组来验证输入:

php
use Filament\Tables\Columns\SelectColumn;

SelectColumn::make('status')
    ->options([
        'draft' => 'Draft',
        'reviewing' => 'Reviewing',
        'published' => 'Published',
    ])
    ->rules(['required'])

有效选项验证(in 规则)

in 规则确保用户无法选择不在选项列表中的选项。这对数据完整性很重要,因此 Filament 默认对所有选择字段应用该规则。

由于选择字段填充选项的方式很多,且许多情况下选项默认不会全部加载到选择器中、需要搜索才能获取,Filament 使用是否存在有效的「选项标签」来判断所选值是否存在。它还会检查该选项是否被禁用

若使用自定义搜索查询检索选项,应确保定义了 getOptionLabelUsing() 方法,以便 Filament 能对照可用选项验证所选值:

php
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() 方法会自动为你定义,因此无需担心。

生命周期钩子

可使用钩子在选择器生命周期的各个时刻执行代码:

php
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 的资源授权。