Modales
Introducción
Las actions pueden requerir confirmación o entrada adicional del usuario antes de ejecutarse. Puedes abrir un modal antes de que se ejecute una action para hacer esto.
Modales de confirmación
Puedes requerir confirmación antes de que se ejecute una action usando el método requiresConfirmation(). Esto es útil para actions particularmente destructivas, como aquellas que eliminan registros.
use App\Models\Post;
use Filament\Actions\Action;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
El modal de confirmación no está disponible cuando se establece un url() en lugar de un action(). En su lugar, debes redirigir a la URL dentro del closure action().
Controlar el contenido del modal
Personalizar el encabezado, descripción y etiqueta de la acción de envío del modal
Puedes personalizar el encabezado, la descripción y la etiqueta del botón de envío en el modal:
use App\Models\Post;
use Filament\Actions\Action;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->modalHeading('Delete post')
->modalDescription('Are you sure you\'d like to delete this post? This cannot be undone.')
->modalSubmitActionLabel('Yes, delete it')
Renderizar un schema en un modal
Filament te permite renderizar un schema en un modal, lo que te permite renderizar cualquiera de los componentes disponibles para construir una interfaz de usuario. Por lo general, es útil construir un formulario en el schema que pueda recopilar información adicional del usuario antes de que se ejecute la action, pero se puede renderizar cualquier interfaz de usuario:
use Filament\Actions\Action;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Components\Section;
Action::make('viewUser')
->schema([
Grid::make(2)
->schema([
Section::make('Details')
->schema([
TextInput::make('name'),
Select::make('position')
->options([
'developer' => 'Developer',
'designer' => 'Designer',
]),
Checkbox::make('is_admin'),
]),
Section::make('Auditing')
->schema([
TextEntry::make('created_at')
->dateTime(),
TextEntry::make('updated_at')
->dateTime(),
]),
]),
])
Información de inyección de utilidades
Además de permitir un valor estático, el método schema() también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
Renderizar un formulario en un modal
Puedes usar campos de formulario para crear formularios de modal de action. Los datos del formulario están disponibles en el array $data del closure action():
use App\Models\Post;
use App\Models\User;
use Filament\Actions\Action;
use Filament\Forms\Components\Select;
Action::make('updateAuthor')
->schema([
Select::make('authorId')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->required(),
])
->action(function (array $data, Post $record): void {
$record->author()->associate($data['authorId']);
$record->save();
})
Llenar el formulario con datos existentes
Puedes llenar el formulario con datos existentes, usando el método fillForm():
use App\Models\Post;
use App\Models\User;
use Filament\Actions\Action;
use Filament\Forms\Components\Select;
Action::make('updateAuthor')
->fillForm(fn (Post $record): array => [
'authorId' => $record->author->id,
])
->schema([
Select::make('authorId')
->label('Author')
->options(User::query()->pluck('name', 'id'))
->required(),
])
->action(function (array $data, Post $record): void {
$record->author()->associate($data['authorId']);
$record->save();
})
Información de inyección de utilidades
El método fillForm() también acepta una función para calcular dinámicamente los datos con los que llenar el formulario. Puedes inyectar varias utilidades en la función como parámetros.
Deshabilitar todos los campos del formulario
Es posible que desees deshabilitar todos los campos del formulario en el modal, asegurándote de que el usuario no pueda editarlos. Puedes hacerlo usando el método disabledForm():
use App\Models\Post;
use Filament\Actions\Action;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
Action::make('approvePost')
->schema([
TextInput::make('title'),
Textarea::make('content'),
])
->disabledForm()
->action(function (Post $record): void {
$record->approve();
})
Renderizar un wizard en un modal
Puedes crear un wizard de formulario multipaso dentro de un modal. En lugar de usar un schema(), define un array steps() y pasa tus objetos Step:
use Filament\Actions\Action;
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Wizard\Step;
Action::make('create')
->steps([
Step::make('Name')
->description('Give the category a unique name')
->schema([
TextInput::make('name')
->required()
->live()
->afterStateUpdated(fn ($state, callable $set) => $set('slug', Str::slug($state))),
TextInput::make('slug')
->disabled()
->required()
->unique(Category::class, 'slug'),
])
->columns(2),
Step::make('Description')
->description('Add some extra details')
->schema([
MarkdownEditor::make('description'),
]),
Step::make('Visibility')
->description('Control who can view it')
->schema([
Toggle::make('is_visible')
->label('Visible to customers.')
->default(true),
]),
])
Agregar un icono dentro del modal
Puedes agregar un icono dentro del modal usando el método modalIcon():
use App\Models\Post;
use Filament\Actions\Action;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->modalIcon('heroicon-o-trash')
Información de inyección de utilidades
El método modalIcon() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
De forma predeterminada, el icono heredará el color del botón de la action. Puedes personalizar el color del icono usando el método modalIconColor():
use App\Models\Post;
use Filament\Actions\Action;
Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->color('danger')
->modalIcon('heroicon-o-trash')
->modalIconColor('warning')
Información de inyección de utilidades
El método modalIconColor() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Personalizar la alineación del contenido del modal
De forma predeterminada, el contenido del modal se alineará al inicio, o se centrará si el modal tiene un ancho de xs o sm. Si deseas cambiar la alineación del contenido en un modal, puedes usar el método modalAlignment() y pasarle Alignment::Start o Alignment::Center:
use Filament\Actions\Action;
use Filament\Support\Enums\Alignment;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->modalAlignment(Alignment::Center)
Información de inyección de utilidades
El método modalAlignment() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Hacer que el encabezado del modal sea fijo
El encabezado de un modal se desplaza fuera de la vista con el contenido del modal cuando este excede el tamaño del modal. Sin embargo, los slide-overs tienen un encabezado fijo que siempre es visible. Puedes controlar este comportamiento usando stickyModalHeader():
use Filament\Actions\Action;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->stickyModalHeader()
Hacer que el pie de página del modal sea fijo
El pie de página de un modal se renderiza en línea después del contenido de forma predeterminada. Los slide-overs, sin embargo, tienen un pie de página fijo que siempre se muestra al desplazarse por el contenido. Puedes habilitar esto para un modal también usando stickyModalFooter():
use Filament\Actions\Action;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->stickyModalFooter()
Contenido personalizado del modal
Puedes definir contenido personalizado para ser renderizado dentro de tu modal, que puedes especificar pasando una vista Blade al método modalContent():
use App\Models\Post;
use Filament\Actions\Action;
Action::make('advance')
->action(fn (Post $record) => $record->advance())
->modalContent(view('filament.pages.actions.advance'))
Información de inyección de utilidades
El método modalContent() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Pasar datos al contenido personalizado del modal
Puedes pasar datos a la vista devolviéndolos desde una función. Por ejemplo, si el $record de una action está establecido, puedes pasarlo a la vista:
use Filament\Actions\Action;
use Illuminate\Contracts\View\View;
Action::make('advance')
->action(fn (Contract $record) => $record->advance())
->modalContent(fn (Contract $record): View => view(
'filament.pages.actions.advance',
['record' => $record],
))
Agregar contenido personalizado del modal debajo del formulario
De forma predeterminada, el contenido personalizado se muestra encima del formulario del modal si hay uno, pero puedes agregar contenido debajo usando modalContentFooter() si lo deseas:
use App\Models\Post;
use Filament\Actions\Action;
Action::make('advance')
->action(fn (Post $record) => $record->advance())
->modalContentFooter(view('filament.pages.actions.advance'))
Información de inyección de utilidades
El método modalContentFooter() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Agregar una action al contenido personalizado del modal
Puedes agregar un botón de action a tu contenido personalizado del modal, lo cual es útil si deseas agregar un botón que realice una action diferente a la action principal. Puedes hacer esto registrando una action con el método registerModalActions(), y luego pasándola a la vista:
use App\Models\Post;
use Filament\Actions\Action;
use Illuminate\Contracts\View\View;
Action::make('advance')
->registerModalActions([
Action::make('report')
->requiresConfirmation()
->action(fn (Post $record) => $record->report()),
])
->action(fn (Post $record) => $record->advance())
->modalContent(fn (Action $action): View => view(
'filament.pages.actions.advance',
['action' => $action],
))
Ahora, en el archivo de vista, puedes renderizar el botón de action llamando a getModalAction():
<div>
{{ $action->getModalAction('report') }}
</div>
Usar un slide-over en lugar de un modal
Puedes abrir un diálogo "slide-over" en lugar de un modal usando el método slideOver():
use Filament\Actions\Action;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->slideOver()
En lugar de abrirse en el centro de la pantalla, el contenido del modal ahora se deslizará desde la derecha y consumirá toda la altura del navegador.
Cambiar el ancho del modal
Puedes cambiar el ancho del modal usando el método modalWidth(). Las opciones corresponden a la escala de ancho máximo de Tailwind. Las opciones son ExtraSmall, Small, Medium, Large, ExtraLarge, TwoExtraLarge, ThreeExtraLarge, FourExtraLarge, FiveExtraLarge, SixExtraLarge, SevenExtraLarge y Screen:
use Filament\Actions\Action;
use Filament\Support\Enums\Width;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->modalWidth(Width::FiveExtraLarge)
Información de inyección de utilidades
El método modalWidth() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Ejecutar código cuando se abre el modal
Puedes ejecutar código dentro de un closure cuando se abre el modal, pasándolo al método mountUsing():
use Filament\Actions\Action;
use Filament\Schemas\Schema;
Action::make('create')
->mountUsing(function (Schema $form) {
$form->fill();
// ...
})
El método
mountUsing(), de forma predeterminada, es utilizado por Filament para inicializar el formulario. Si sobrescribes este método, necesitarás llamar a$form->fill()para asegurar que el formulario se inicialice correctamente. Si deseas poblar el formulario con datos, puedes hacerlo pasando un array al métodofill(), en lugar de usarfillForm()en la action misma.
Personalizar los botones de action en el pie de página del modal
De forma predeterminada, hay dos actions en el pie de página de un modal. La primera es un botón para enviar, que ejecuta el action(). El segundo botón cierra el modal y cancela la action.
Modificar el botón de action del pie de página del modal predeterminado
Para modificar la instancia de action que se utiliza para renderizar uno de los botones de action predeterminados, puedes pasar un closure a los métodos modalSubmitAction() y modalCancelAction():
use Filament\Actions\Action;
Action::make('help')
->modalContent(view('actions.help'))
->modalCancelAction(fn (Action $action) => $action->label('Close'))
Los métodos disponibles para personalizar botones de activación funcionarán para modificar la instancia $action dentro del closure.
Para personalizar las etiquetas de los botones en tu modal, se pueden usar los métodos modalSubmitActionLabel() y modalCancelActionLabel() en lugar de pasar una función a modalSubmitAction() y modalCancelAction(), si no requieres ninguna otra personalización.
Eliminar un botón de action del pie de página del modal predeterminado
Para eliminar una action predeterminada, puedes pasar false a modalSubmitAction() o modalCancelAction():
use Filament\Actions\Action;
Action::make('help')
->modalContent(view('actions.help'))
->modalSubmitAction(false)
Agregar un botón de action adicional al pie de página del modal
Puedes pasar un array de actions adicionales para ser renderizadas, entre las actions predeterminadas, en el pie de página del modal usando el método extraModalFooterActions():
use Filament\Actions\Action;
Action::make('create')
->schema([
// ...
])
// ...
->extraModalFooterActions(fn (Action $action): array => [
$action->makeModalSubmitAction('createAnother', arguments: ['another' => true]),
])
Información de inyección de utilidades
El método extraModalFooterActions() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
$action->makeModalSubmitAction() devuelve una instancia de action que puede ser personalizada usando los métodos disponibles para personalizar botones de activación.
El segundo parámetro de makeModalSubmitAction() te permite pasar un array de argumentos que serán accesibles dentro del closure action() de la action como $arguments. Estos podrían ser útiles como indicadores para indicar que la action debe comportarse de manera diferente según la decisión del usuario:
use Filament\Actions\Action;
Action::make('create')
->schema([
// ...
])
// ...
->extraModalFooterActions(fn (Action $action): array => [
$action->makeModalSubmitAction('createAnother', arguments: ['another' => true]),
])
->action(function (array $data, array $arguments): void {
// Crear
if ($arguments['another'] ?? false) {
// Restablecer el formulario y no cerrar el modal
}
})
Abrir otro modal desde una action de pie de página adicional
Puedes anidar actions unas dentro de otras, lo que te permite abrir un nuevo modal desde una action de pie de página adicional:
use Filament\Actions\Action;
Action::make('edit')
// ...
->extraModalFooterActions([
Action::make('delete')
->requiresConfirmation()
->action(function () {
// ...
}),
])
Ahora, el modal de edición tendrá un botón "Delete" en el pie de página, que abrirá un modal de confirmación cuando se haga clic en él. Esta action es completamente independiente de la action edit, y no ejecutará la action edit cuando se haga clic en ella.
En este ejemplo, sin embargo, probablemente desees cancelar la action edit si se ejecuta la action delete. Puedes hacer esto usando el método cancelParentActions():
use Filament\Actions\Action;
Action::make('delete')
->requiresConfirmation()
->action(function () {
// ...
})
->cancelParentActions()
Si tienes anidamiento profundo con múltiples actions padre, pero no deseas cancelar todas ellas, puedes pasar el nombre de la action padre que deseas cancelar, incluidos sus hijos, a cancelParentActions():
use Filament\Actions\Action;
Action::make('first')
->requiresConfirmation()
->action(function () {
// ...
})
->extraModalFooterActions([
Action::make('second')
->requiresConfirmation()
->action(function () {
// ...
})
->extraModalFooterActions([
Action::make('third')
->requiresConfirmation()
->action(function () {
// ...
})
->extraModalFooterActions([
Action::make('fourth')
->requiresConfirmation()
->action(function () {
// ...
})
->cancelParentActions('second'),
]),
]),
])
En este ejemplo, si se ejecuta la action fourth, la action second se cancela, pero también lo hace la action third ya que es hija de second. Sin embargo, la action first no se cancela, ya que es la padre de second. El modal de la action first permanecerá abierto.
Acceder a información sobre actions padre desde una hija
Puedes acceder a las instancias de actions padre y sus datos y argumentos sin procesar inyectando el array $mountedActions en una función utilizada por tu action anidada. Por ejemplo, para obtener la action padre de nivel superior actualmente activa en la página, puedes usar $mountedActions[0]. Desde allí, puedes obtener los datos sin procesar para esa action llamando a $mountedActions[0]->getRawData(). Ten en cuenta que los datos sin procesar no están validados ya que la action aún no se ha enviado:
use Filament\Actions\Action;
use Filament\Forms\Components\TextInput;
Action::make('first')
->schema([
TextInput::make('foo'),
])
->action(function () {
// ...
})
->extraModalFooterActions([
Action::make('second')
->requiresConfirmation()
->action(function (array $mountedActions) {
dd($mountedActions[0]->getRawData());
// ...
}),
])
Puedes hacer algo similar con los argumentos actuales para una action padre, con el método $mountedActions[0]->getArguments().
Incluso si tienes múltiples capas de anidamiento, el array $mountedActions contendrá cada action que esté actualmente activa, por lo que puedes acceder a información sobre ellas:
use Filament\Actions\Action;
Action::make('first')
->schema([
TextInput::make('foo'),
])
->action(function () {
// ...
})
->extraModalFooterActions([
Action::make('second')
->schema([
TextInput::make('bar'),
])
->arguments(['number' => 2])
->action(function () {
// ...
})
->extraModalFooterActions([
Action::make('third')
->schema([
TextInput::make('baz'),
])
->arguments(['number' => 3])
->action(function () {
// ...
})
->extraModalFooterActions([
Action::make('fourth')
->requiresConfirmation()
->action(function (array $mountedActions) {
dd(
$mountedActions[0]->getRawData(),
$mountedActions[0]->getArguments(),
$mountedActions[1]->getRawData(),
$mountedActions[1]->getArguments(),
$mountedActions[2]->getRawData(),
$mountedActions[2]->getArguments(),
);
// ...
}),
]),
]),
])
Cerrar el modal
Cerrar el modal haciendo clic fuera
De forma predeterminada, cuando haces clic fuera de un modal, este se cerrará. Si deseas deshabilitar este comportamiento para una action específica, puedes usar el método closeModalByClickingAway(false):
use Filament\Actions\Action;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->closeModalByClickingAway(false)
Información de inyección de utilidades
El método closeModalByClickingAway() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Si deseas cambiar el comportamiento para todos los modales en la aplicación, puedes hacerlo llamando a ModalComponent::closedByClickingAway() dentro de un service provider o middleware:
use Filament\Support\View\Components\ModalComponent;
ModalComponent::closedByClickingAway(false);
Cerrar el modal presionando escape
De forma predeterminada, cuando presionas escape en un modal, este se cerrará. Si deseas deshabilitar este comportamiento para una action específica, puedes usar el método closeModalByEscaping(false):
use Filament\Actions\Action;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->closeModalByEscaping(false)
Información de inyección de utilidades
El método closeModalByEscaping() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Si deseas cambiar el comportamiento para todos los modales en la aplicación, puedes hacerlo llamando a ModalComponent::closedByEscaping() dentro de un service provider o middleware:
use Filament\Support\View\Components\ModalComponent;
ModalComponent::closedByEscaping(false);
Ocultar el botón de cerrar del modal
De forma predeterminada, los modales tienen un botón de cerrar en la esquina superior derecha. Si deseas ocultar el botón de cerrar, puedes usar el método modalCloseButton(false):
use Filament\Actions\Action;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->modalCloseButton(false)
Información de inyección de utilidades
El método modalCloseButton() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Si deseas ocultar el botón de cerrar para todos los modales en la aplicación, puedes hacerlo llamando a ModalComponent::closeButton(false) dentro de un service provider o middleware:
use Filament\Support\View\Components\ModalComponent;
ModalComponent::closeButton(false);
Prevenir que el modal se enfoque automáticamente
De forma predeterminada, los modales se enfocarán automáticamente en el primer elemento enfocable cuando se abran. Si deseas deshabilitar este comportamiento, puedes usar el método modalAutofocus(false):
use Filament\Actions\Action;
Action::make('updateAuthor')
->schema([
// ...
])
->action(function (array $data): void {
// ...
})
->modalAutofocus(false)
Información de inyección de utilidades
El método modalAutofocus() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Si deseas deshabilitar el enfoque automático para todos los modales en la aplicación, puedes hacerlo llamando a ModalComponent::autofocus(false) dentro de un service provider o middleware:
use Filament\Support\View\Components\ModalComponent;
ModalComponent::autofocus(false);
Optimizar métodos de configuración del modal
Cuando usas consultas de base de datos u otras operaciones pesadas dentro de métodos de configuración del modal como modalHeading(), pueden ejecutarse más de una vez. Esto es porque Filament usa estos métodos para decidir si renderizar el modal o no, y también para renderizar el contenido del modal.
Para omitir la verificación que Filament hace para decidir si renderizar el modal, puedes usar el método modal(), que informará a Filament que el modal existe para esta action, y no necesita verificar de nuevo:
use Filament\Actions\Action;
Action::make('updateAuthor')
->modal()
Ocultar condicionalmente el modal
Es posible que necesites mostrar condicionalmente un modal por razones de confirmación mientras regresas a la action predeterminada. Esto se puede lograr usando modalHidden():
use Filament\Actions\Action;
Action::make('create')
->action(function (array $data): void {
// ...
})
->modalHidden($this->role !== 'admin')
->modalContent(view('filament.pages.actions.create'))
Información de inyección de utilidades
El método modalHidden() también acepta una función para calcular dinámicamente el valor. Puedes inyectar varias utilidades en la función como parámetros.
Agregar atributos adicionales a la ventana del modal
Puedes pasar atributos HTML adicionales a la ventana del modal a través del método extraModalWindowAttributes(), que se fusionarán en su elemento HTML externo. Los atributos deben ser representados por un array, donde la clave es el nombre del atributo y el valor es el valor del atributo:
use Filament\Actions\Action;
Action::make('updateAuthor')
->extraModalWindowAttributes(['class' => 'update-author-modal'])
Información de inyección de utilidades
Además de permitir un valor estático, el método extraModalWindowAttributes() también acepta una función para calcularlo dinámicamente. Puedes inyectar varias utilidades en la función como parámetros.
De forma predeterminada, llamar a extraModalWindowAttributes() varias veces sobrescribirá los atributos anteriores. Si deseas fusionar los atributos en su lugar, puedes pasar merge: true al método.