Columna de selección
Introducción
La columna de selección te permite renderizar un campo select dentro de la tabla, que puede usarse para actualizar ese registro de la base de datos sin necesidad de abrir una nueva página o modal.
Debes pasar opciones a la columna:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
Habilitar el select de JavaScript
Por defecto, Filament usa el select HTML5 nativo. Puedes habilitar un select de JavaScript más personalizable usando el método native(false)
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->native(false)
💡 Utility Injection
Además de permitir un valor estático, el método native()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Buscar opciones
Puedes habilitar un campo de búsqueda para permitir acceso más fácil a muchas opciones, usando el método searchableOptions()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->searchableOptions()
Opcionalmente, puedes pasar un valor booleano para controlar si el campo debe ser buscable o no:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->searchableOptions(FeatureFlag::active())
💡 Utility Injection
Además de permitir un valor estático, el método searchableOptions()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Devolver resultados de búsqueda personalizados
Si tienes muchas opciones y quieres poblarlas basándote en una búsqueda de base de datos u otra fuente de datos externa, puedes usar los métodos getOptionsSearchResultsUsing()
y getOptionLabelUsing()
en lugar de options()
.
El método getOptionsSearchResultsUsing()
acepta un callback que devuelve resultados de búsqueda en formato $key => $value
. La búsqueda actual del usuario está disponible como $search
, y debes usarla para filtrar tus resultados.
El método getOptionLabelUsing()
acepta un callback que transforma el $value
de la opción seleccionada en una etiqueta. Esto se usa cuando el formulario se carga por primera vez cuando el usuario aún no ha hecho una búsqueda. De lo contrario, la etiqueta usada para mostrar la opción actualmente seleccionada no estaría disponible.
Tanto getOptionsSearchResultsUsing()
como getOptionLabelUsing()
deben usarse en el select si quieres proporcionar resultados de búsqueda personalizados:
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()
es crucial, ya que proporciona a Filament la etiqueta de la opción seleccionada, por lo que no necesita ejecutar una búsqueda completa para encontrarla. Si una opción no es válida, debe devolver null
.
💡 Utility Injection
Puedes inyectar varias utilidades en estas funciones como parámetros.
Establecer un mensaje de carga personalizado
Cuando uses un select o multi-select buscable, puedes querer mostrar un mensaje personalizado mientras las opciones se están cargando. Puedes hacer esto usando el método optionsLoadingMessage()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsLoadingMessage('Cargando autores...')
💡 Utility Injection
Además de permitir un valor estático, el método optionsLoadingMessage()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Establecer un mensaje personalizado para sin resultados de búsqueda
Cuando uses un select o multi-select buscable, puedes querer mostrar un mensaje personalizado cuando no se encuentren resultados de búsqueda. Puedes hacer esto usando el método noOptionsSearchResultsMessage()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->noOptionsSearchResultsMessage('No se encontraron autores.')
💡 Utility Injection
Además de permitir un valor estático, el método noOptionsSearchResultsMessage()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Establecer un prompt de búsqueda personalizado
Cuando uses un select o multi-select buscable, puedes querer mostrar un mensaje personalizado cuando el usuario aún no ha introducido un término de búsqueda. Puedes hacer esto usando el método optionsSearchPrompt()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions(['name', 'email'])
->optionsSearchPrompt('Buscar autores por su nombre o dirección de email')
💡 Utility Injection
Además de permitir un valor estático, el método optionsSearchPrompt()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Establecer un mensaje de búsqueda personalizado
Cuando uses un select o multi-select buscable, puedes querer mostrar un mensaje personalizado mientras los resultados de búsqueda se están cargando. Puedes hacer esto usando el método optionsSearchingMessage()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsSearchingMessage('Buscando autores...')
💡 Utility Injection
Además de permitir un valor estático, el método optionsSearchingMessage()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Ajustar el debounce de búsqueda
Por defecto, Filament esperará 1000 milisegundos (1 segundo) antes de buscar opciones cuando el usuario escriba en un select o multi-select buscable. También esperará 1000 milisegundos entre búsquedas, si el usuario está escribiendo continuamente en el campo de búsqueda. Puedes cambiar esto usando el método optionsSearchDebounce()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsSearchDebounce(500)
Asegúrate de no reducir demasiado el debounce, ya que esto puede hacer que el select se vuelva lento y no responda debido a un alto número de peticiones de red para recuperar opciones del servidor.
💡 Utility Injection
Además de permitir un valor estático, el método optionsSearchDebounce()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Integrar con una relación Eloquent
Puedes emplear el método optionsRelationship()
del SelectColumn
para configurar una relación BelongsTo
para recuperar automáticamente opciones. El titleAttribute
es el nombre de una columna que se usará para generar una etiqueta para cada opción:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
Buscar opciones de relación en múltiples columnas
Por defecto, si el select también es buscable, Filament devolverá resultados de búsqueda para la relación basados en la columna título de la relación. Si quieres buscar en múltiples columnas, puedes pasar un array de columnas al método searchableOptions()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions(['name', 'email'])
Precargar opciones de relación
Si quieres poblar las opciones buscables desde la base de datos cuando se carga la página, en lugar de cuando el usuario busca, puedes usar el método preloadOptions()
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->preloadOptions()
Opcionalmente, puedes pasar un valor booleano para controlar si el campo debe precargarse o no:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->preload(FeatureFlag::active())
💡 Utility Injection
Además de permitir un valor estático, el método preload()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Excluir el registro actual
Cuando trabajas con relaciones recursivas, probablemente querrás remover el registro actual del conjunto de resultados.
Esto se puede hacer fácilmente usando el argumento ignoreRecord
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('parent_id')
->optionsRelationship(name: 'parent', titleAttribute: 'name', ignoreRecord: true)
Personalizar la consulta de relación
Puedes personalizar la consulta de base de datos que recupera opciones usando el tercer parámetro del método 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(),
)
💡 Utility Injection
El argumento modifyQueryUsing
puede inyectar varias utilidades en la función como parámetros.
Personalizar las etiquetas de opciones de relación
Si quieres personalizar la etiqueta de cada opción, tal vez para ser más descriptiva, o para concatenar un nombre y apellido, podrías usar una columna virtual en tu migración de base de datos:
$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')
Alternativamente, puedes usar el método getOptionLabelFromRecordUsing()
para transformar el modelo Eloquent de una opción en una etiqueta:
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'])
💡 Utility Injection
El método getOptionLabelFromRecordUsing()
puede inyectar varias utilidades en la función como parámetros.
Recordar opciones
Por defecto, cuando usas optionsRelationship()
, Filament recordará las opciones durante la duración de la página de tabla para mejorar el rendimiento. Esto significa que la función de opciones solo se ejecutará una vez por página de tabla en lugar de una vez por celda. Puedes desactivar este comportamiento usando el método rememberOptions(false)
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->rememberOptions(false)
Cuando las opciones se recuerdan, cualquier opción específica del registro u opciones deshabilitadas no funcionarán correctamente, ya que se usarán las mismas opciones para todos los registros en la tabla. Si necesitas opciones específicas del registro u opciones deshabilitadas, debes desactivar el recordar opciones.
💡 Utility Injection
Además de permitir un valor estático, el método rememberOptions()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Permitir HTML en las etiquetas de opciones
Por defecto, Filament escapará cualquier HTML en las etiquetas de opciones. Si quieres permitir HTML, puedes usar el método 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()
Ten en cuenta que necesitarás asegurar que el HTML sea seguro para renderizar, de lo contrario tu aplicación será vulnerable a ataques XSS.
Opcionalmente, puedes pasar un valor booleano para controlar si el campo debe permitir HTML o no:
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())
💡 Utility Injection
Además de permitir un valor estático, el método allowOptionsHtml()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Ajustar o truncar etiquetas de opciones
Cuando uses el select de JavaScript, las etiquetas que excedan el ancho del elemento select se ajustarán a múltiples líneas por defecto. Alternativamente, puedes elegir truncar las etiquetas que se desborden.
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('truncate')
->wrapOptionLabels(false)
💡 Utility Injection
Además de permitir un valor estático, el método wrapOptionLabels()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Desactivar la selección de placeholder
Puedes prevenir que el placeholder (opción null) sea seleccionado usando el método selectablePlaceholder(false)
:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->selectablePlaceholder(false)
💡 Utility Injection
Además de permitir un valor estático, el método selectablePlaceholder()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Desactivar opciones específicas
Puedes desactivar opciones específicas usando el método disableOptionWhen()
. Acepta un closure, en el cual puedes verificar si la opción con un $value
específico debe desactivarse:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->default('draft')
->disableOptionWhen(fn (string $value): bool => $value === 'published')
💡 Utility Injection
Puedes inyectar varias utilidades en la función como parámetros.
Limitar el número de opciones
Puedes limitar el número de opciones que se muestran en un select o multi-select buscable usando el método optionsLimit()
. El valor por defecto es 50:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('author_id')
->optionsRelationship(name: 'author', titleAttribute: 'name')
->searchableOptions()
->optionsLimit(20)
Asegúrate de no elevar demasiado el límite, ya que esto puede hacer que el select se vuelva lento y no responda debido al alto uso de memoria en el navegador.
💡 Utility Injection
Además de permitir un valor estático, el método optionsLimit()
también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Validación
Puedes validar la entrada pasando cualquier regla de validación de Laravel en un array:
use Filament\Tables\Columns\SelectColumn;
SelectColumn::make('status')
->options([
'draft' => 'Draft',
'reviewing' => 'Reviewing',
'published' => 'Published',
])
->rules(['required'])
Validación de opciones válidas (regla in
)
La regla in
asegura que los usuarios no puedan seleccionar una opción que no esté en la lista de opciones. Esta es una regla importante para propósitos de integridad de datos, por lo que Filament la aplica por defecto a todos los campos select.
Dado que hay muchas formas para que un campo select pueble sus opciones, y en muchos casos las opciones no se cargan todas en el select por defecto y requieren búsqueda para recuperarlas, Filament usa la presencia de una "etiqueta de opción" válida para determinar si el valor seleccionado existe. También verifica si esa opción está desactivada o no.
Si estás usando una consulta de búsqueda personalizada para recuperar opciones, debes asegurar que el método getOptionLabelUsing()
esté definido, para que Filament pueda validar el valor seleccionado contra las opciones disponibles:
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),
El método getOptionLabelUsing()
debe devolver null
si la opción no es válida, para permitir que Filament determine que el valor seleccionado no está en la lista de opciones. Si la opción es válida, debe devolver la etiqueta de la opción.
Si estás usando el método optionsRelationship()
, el método getOptionLabelUsing()
se definirá automáticamente para ti, por lo que no necesitas preocuparte por ello.
Hooks del ciclo de vida
Los hooks pueden usarse para ejecutar código en varios puntos dentro del ciclo de vida del select:
SelectColumn::make()
->beforeStateUpdated(function ($record, $state) {
// Se ejecuta antes de que el estado se guarde en la base de datos.
})
->afterStateUpdated(function ($record, $state) {
// Se ejecuta después de que el estado se guarde en la base de datos.
})