跳到主要内容
版本:3.x

模态框

概述

Action 可能会在运行前要求额外确认或者用户输入。你可以在 Action 执行之前打开模态框实现该功能。

确认模态框

使用 requiresConfirmation() 方法,你可以在 Action 运行之前请求确认。这对于破坏性操作,比如删除记录,特别有用。

use App\Models\Post;

Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
Confirmation modal

如果使用 url() 代替 action(),那确认模态框不可用。相反,你应该在 action() 方法内,重定向 URL。

模态框表单

你也可以在模态框中渲染表单,在 Action 运行之前从用户那边收集额外的信息。

你可以使用表单构造器中的组件来创建自定义模态框表单。表单中的数据可以通过 action() 闭包中的 $data 数组获取:

use App\Models\Post;
use App\Models\User;
use Filament\Forms\Components\Select;

Action::make('updateAuthor')
->form([
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();
})
Modal with form

使用现有数据填充表单

通过 fillForm() 方法,你可以使用现有数据填充表单:

use App\Models\Post;
use App\Models\User;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;

Action::make('updateAuthor')
->fillForm(fn (Post $record): array => [
'authorId' => $record->author->id,
])
->form([
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();
})

使用 Wizard 作为模态框表单

你可以在模态框中创建多步骤表单向导卡(wizard)。定义 step() 字符串,并传入 Step 对象:

use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\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),
]),
])
Modal with wizard

禁用所有表单字段

你可以使用 disabledForm() 方法,禁用模态框中的所有表单字段,确保用户不能对其进行编辑:

use App\Models\Post;
use App\Models\User;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;

Action::make('approvePost')
->form([
TextInput::make('title'),
Textarea::make('content'),
])
->fillForm(fn (Post $record): array => [
'title' => $record->title,
'content' => $record->content,
])
->disabledForm()
->action(function (Post $record): void {
$record->approve();
})

自定义模态框标题、描述及按钮标签

你可以自定义模态框的标题、描述及提交按钮标签:

use App\Models\Post;

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')
Confirmation modal with custom text

在模态框中添加图标

使用 modalIcon() 方法,你可以在模态框中添加图标

use App\Models\Post;

Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->modalIcon('heroicon-o-trash')
Confirmation modal with icon

默认情况下,图标继承了 Action 按钮的颜色。你可以使用 modalIconColor() 方法自定义图标颜色:

use App\Models\Post;

Action::make('delete')
->action(fn (Post $record) => $record->delete())
->requiresConfirmation()
->color('danger')
->modalIcon('heroicon-o-trash')
->modalIconColor('warning')

自定义模态框内容的对齐方式

默认情况下,模态框内容对齐到起始位置,或者如果模态框宽度xssm,则对齐到中间。如果你想修改模态框内容的对齐方式,可以在 modalAlignment() 中传入 Alignment::Start 或者 Alignment::Center

use Filament\Support\Enums\Alignment;

Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->modalAlignment(Alignment::Center)

自定义模态框内容

你可以将 Blade 视图传入 modalContent() 函数,在模态框中渲染自定义内容。

use App\Models\Post;

Action::make('advance')
->action(fn (Post $record) => $record->advance())
->modalContent(view('filament.pages.actions.advance'))

传递数据到自定义模态框内容

你可以通过返回函数,将数据传递到视图中。比如,如果设置了 Action 的 $record,你可以将其传入到视图中:

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],
))

在表单下添加自定义模态框内容

默认情况下,如果有自定义内容的话,它们会展示在模态框表单之上,不过你可以使用 modalContentFooter() 将内容添加到表单下面:

use App\Models\Post;

Action::make('advance')
->action(fn (Post $record) => $record->advance())
->modalContentFooter(view('filament.pages.actions.advance'))

添加 Action 到自定义模态框内容

你可以添加 Action 按钮到自定义模态框内容,如果你想添加按钮执行一个 Action(非主 Action),这就有用。你可以使用 registerModalActions() 方法注册 Action,并将其传入到视图中:

use App\Models\Post;
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],
))

现在,在视图文件中,你可以调用 getModalAction() 来渲染 Action 按钮:

<div>
{{ $action->getModalAction('report') }}
</div>

使用 SlideOver 替代模态框

使用 slideOver() 方法,你可以打开 slide-over 对话框,而非模态框:

Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->slideOver()
Slide over with form

不再是在屏幕的中间打开,模态框内容现在会从右边滑入(slide in)并消费浏览器的全部高度。

粘性模态框 Header

当模态框内容超过模态框大小时,模态框的 Header 会滚动出屏幕。不过,SlideOver 使用了粘性 Header,使之总是可见。你可以使用 stickyModalHeader() 控制该行为:

Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->stickyModalHeader()

默认情况下,模态框的 Footer 在内容之后进行行内渲染。不过,SlideOver 拥有一个粘性的 Footer,使之在内容滚动时总是显示。使用 stickyModalFooter(),你可以为模态框启用该功能:

Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->stickyModalFooter()

修改模态框宽度

使用 modalWidth() 方法,你可以修改模态框宽度。宽度选项对应于 Tailwind 的 max-width 大小。可用选项包括 ExtraSmall, Small, Medium, Large, ExtraLarge, TwoExtraLarge, ThreeExtraLarge, FourExtraLarge, FiveExtraLarge, SixExtraLarge, SevenExtraLarge, Screen

Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->modalWidth(MaxWidth::FiveExtraLarge)

模态框打开时执行代码

使用 mountUsing() 方法,你可以在模态框打开时,在闭包中执行代码。

use Filament\Forms\Form;

Action::make('create')
->mountUsing(function (Form $form) {
$form->fill();

// ...
})

默认情况下,Filament 使用 mountUsing() 方法去初始化表单。如果重写该方法,你需要调用 $form->fill() 以确保表单正确初始化。如果你想要使用数据填充表单,你可以传入数组到 fill() 方法中,而不是在 Action 中使用 fillForm() 方法

默认情况下,模态框的 Footer 中有两个 Action。第一个是提交按钮,它将执行该 Action。第二个按钮关闭模态框并取消 Action。

要修改 Action 实例,使之用于渲染其中一个默认 Action 按钮,你可以传递闭包到 modalSubmitAction()modalCancelAction() 方法:

use Filament\Actions\StaticAction;

Action::make('help')
->modalContent(view('actions.help'))
->modalCancelAction(fn (StaticAction $action) => $action->label('Close'))

自定义触发按钮的可用方法将用于在闭包中修改 $action 实例。

要移除默认 Action,你可用在 modalSubmitAction()modalCancelAction() 中传入 false

Action::make('help')
->modalContent(view('actions.help'))
->modalSubmitAction(false)

使用 extraModalFooterActions() 方法,你可以传递要在默认 Action 之间渲染的额外的 Action 数组:

Action::make('create')
->form([
// ...
])
// ...
->extraModalFooterActions(fn (Action $action): array => [
$action->makeModalSubmitAction('createAnother', arguments: ['another' => true]),
])

$action->makeModalSubmitAction() 返回一个 Action 实例,该实例可以使用触发按钮可用方法进行自定义。

makeModalSubmitAction() 的第二个参数,允许你传递一个参数数组,该参数数组可在 Action 的 action() 闭包中以 $arguments 访问。这可以作为一个标志,用于说明该 Action 可以基于用户决定进行不同操作:

Action::make('create')
->form([
// ...
])
// ...
->extraModalFooterActions(fn (Action $action): array => [
$action->makeModalSubmitAction('createAnother', arguments: ['another' => true]),
])
->action(function (array $data, array $arguments): void {
// Create

if ($arguments['another'] ?? false) {
// Reset the form and don't close the modal
}
})

你可以在 Action 中互相嵌套,这样可以从额外的 Footer Action 中打开新的模态框:

Action::make('edit')
// ...
->extraModalFooterActions([
Action::make('delete')
->requiresConfirmation()
->action(function () {
// ...
}),
])

现在,编辑模态框的 Footer 中有一个 "Delete" 按钮,点击时会打开确认模态框。该 Action 完全独立于 edit Action,点击时不会运行 edit Action。

本例中, 如果 delete Action 运行了,你可能希望取消 edit Aaction。为此,你可以使用 cancelParentActions() 方法:

Action::make('delete')
->requiresConfirmation()
->action(function () {
// ...
})
->cancelParentActions()

如果你使用了深层嵌套,有多个父级 Action;而不想取消所有父级,你可以将你要取消的父级 Action 名及其子 Action 传递给 cancelParentActions()

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'),
]),
]),
])

本例中,如果第四个(fourth) Action 运行了,第二个(second) Action 则会取消,不过,第三个(third) Action 也会取消因为它是 second 的下级。第一个(first) Action 没有取消,不过,它是第二个(second) Action 的父级。第一个 (first) Action 的模态框会保持打开状态,

点击离开关闭模态框

默认情况下,从模态框中点击离开(Click Away),它会自己关闭。如果你想为某个模态框禁用该行为,请使用 closeModalByClickingAway(false) 方法:

Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->closeModalByClickingAway(false)

如果你想改变应用中所有模态框的行为,你可以在服务提供者或中间件中调用 Modal::closedByClickingAway()

use Filament\Support\View\Components\Modal;

Modal::closedByClickingAway(false);

隐藏模态框关闭按钮

默认情况下,模态框在右上脚有一个关闭按钮。如果你想隐藏该关闭按钮,你可以使用 modalCloseButton(fasle) 方法:

Action::make('updateAuthor')
->form([
// ...
])
->action(function (array $data): void {
// ...
})
->modalCloseButton(false)

如果你想在应用中隐藏所有模态框的关闭按钮,你可以在服务提供者或中间件中调用 Modal::closeButton(false)

use Filament\Support\View\Components\Modal;

Modal::closeButton(false);

优化模态框配置方法

当你在模态框配置方法(比如 modalHeading())中使用数据库查询或者其他大型操作时,其可以执行多次。这是因为 Filament 使用这些方法来决定是否渲染模态框,以及渲染模态框的内容。

要跳过这个确定是否渲染模态框的检查,你可以使用 modal() 方法,该方法会告诉 Filament 该模态框存在该 Action 中,且不需要再次检查:

Action::make('updateAuthor')
->modal()

条件性隐藏模态框

你可能需要条件性展示模态框。请使用 modalHidden()

Action::make('create')
->action(function (array $data): void {
// ...
})
->modalHidden(fn (): bool => $this->role !== 'admin')
->modalContent(view('filament.pages.actions.create'))