Skip to content
全部文档

重复器

简介

重复器组件可让你输出由重复表单组件组成的 JSON 数组。

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;

Repeater::make('members')
    ->schema([
        TextInput::make('name')->required(),
        Select::make('role')
            ->options([
                'member' => 'Member',
                'administrator' => 'Administrator',
                'owner' => 'Owner',
            ])
            ->required(),
    ])
    ->columns(2)
重复器重复器

我们建议将重复器数据存储在数据库的 JSON 列中。此外,若使用 Eloquent,请确保该列有 array 类型转换。

如上例所示,组件 schema 可在组件的 schema() 方法中定义:

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;

Repeater::make('members')
    ->schema([
        TextInput::make('name')->required(),
        // ...
    ])

若希望定义可按任意顺序重复的多个 schema 块的重复器,请使用 构建器

设置空的默认项

重复器可以默认创建一定数量的空项。默认值仅在 schema 加载时无数据的情况下使用。在标准 面板资源 中,默认值用于创建页,而非编辑页。要使用默认项,请将项数传给 defaultItems() 方法:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->defaultItems(3)

TIP

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

添加项

重复器下方会显示一个操作按钮,允许用户添加新项。

设置添加操作按钮的标签

你可以使用 addActionLabel() 方法设置标签,以自定义添加重复器项的按钮上显示的文本:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->addActionLabel('Add member')

TIP

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

对齐添加操作按钮

默认情况下,添加操作居中对齐。你可以使用 addActionAlignment() 方法调整,传入 Alignment::StartAlignment::EndAlignment 选项:

php
use Filament\Forms\Components\Repeater;
use Filament\Support\Enums\Alignment;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->addActionAlignment(Alignment::Start)

TIP

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

添加操作左对齐的重复器添加操作左对齐的重复器

阻止用户添加项

你可以使用 addable(false) 方法阻止用户向重复器添加项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->addable(false)

TIP

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

删除项

每项上会显示一个操作按钮,允许用户删除该项。

阻止用户删除项

你可以使用 deletable(false) 方法阻止用户从重复器中删除项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->deletable(false)

TIP

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

重新排序项

每项上会显示一个按钮,允许用户拖放以在列表中重新排序。

阻止用户重新排序项

你可以使用 reorderable(false) 方法阻止用户重新排序重复器中的项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->reorderable(false)

TIP

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

使用按钮重新排序项

你可以使用 reorderableWithButtons() 方法,启用通过上移/下移按钮重新排序项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->reorderableWithButtons()
可用按钮重新排序的重复器可用按钮重新排序的重复器

你也可以传入布尔值,以控制重复器是否应使用按钮排序:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->reorderableWithButtons(FeatureFlag::active())

TIP

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

阻止拖放重新排序

你可以使用 reorderableWithDragAndDrop(false) 方法阻止通过拖放排序项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->reorderableWithDragAndDrop(false)

TIP

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

折叠项

重复器可设为 collapsible(),以便在长表单中按需隐藏内容:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->schema([
        // ...
    ])
    ->collapsible()
可折叠的重复器可折叠的重复器

你也可以默认折叠所有项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->schema([
        // ...
    ])
    ->collapsed()
默认折叠的重复器默认折叠的重复器

你也可以向 collapsible()collapsed() 方法传入布尔值,以控制重复器是否可折叠以及是否默认折叠:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->schema([
        // ...
    ])
    ->collapsible(FeatureFlag::active())
    ->collapsed(FeatureFlag::active())

TIP

除了允许静态值外,collapsible()collapsed() 方法也接受函数以动态计算。你可以将各种工具作为参数注入到这些函数中。

若折叠项包含渲染成本高的组件,可 延迟加载其 schema,直到展开时再加载。

延迟加载重复器项 schema

若重复器的项 schema 渲染成本高,可将 Schema 对象传给 schema() 并使用 deferLoading()。当项默认 折叠 时尤其有用。每个项的 schema 会在该项展开并进入视口时独立加载:

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;

Repeater::make('members')
    ->schema(
        Schema::make()
            ->components([
                TextInput::make('name'),
                TextInput::make('email')
                    ->email(),
            ])
            ->deferLoading(),
    )
    ->collapsed()

重复器项 schema 会自动从其项状态路径获得唯一键。关于延迟 schema 的更多信息,请参阅 schema 概览

克隆项

你可以使用 cloneable() 方法允许复制重复器项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->schema([
        // ...
    ])
    ->cloneable()
可克隆的重复器可克隆的重复器

你也可以向 cloneable() 方法传入布尔值,以控制重复器是否可克隆:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->schema([
        // ...
    ])
    ->cloneable(FeatureFlag::active())

TIP

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

与 Eloquent 关系集成

你可以使用 Repeaterrelationship() 方法配置 HasMany 关系。Filament 会从该关系加载项数据,并在提交表单时写回关系。若未向 relationship() 传入自定义关系名,Filament 将使用字段名作为关系名:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->relationship()
    ->schema([
        // ...
    ])

在关系中重新排序项

默认情况下,关系重复器项的 重新排序 是禁用的。因为相关模型需要一个 sort 列来存储相关记录的顺序。要启用重新排序,可使用 orderColumn() 方法,传入相关模型上用于存储顺序的列名:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->relationship()
    ->schema([
        // ...
    ])
    ->orderColumn('sort')

若使用类似 spatie/eloquent-sortable 且排序列为 order_column,可将其传入 orderColumn()

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->relationship()
    ->schema([
        // ...
    ])
    ->orderColumn('order_column')

TIP

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

BelongsToMany Eloquent 关系集成

有一种常见误解:对重复器使用 BelongsToMany 关系就像使用 HasMany 一样简单。事实并非如此,因为 BelongsToMany 关系需要中间表存储关系数据。重复器将其数据保存到相关模型,而非中间表。因此,若希望将每个重复器项映射到中间表的一行,必须通过带 pivot 模型的 HasMany 关系,才能在 BelongsToMany 场景中使用重复器。

假设你有一个创建新 Order 模型的表单。每个订单属于多个 Product 模型,每个产品也属于多个订单。你有一张 order_product 中间表存储关系数据。与其在重复器上使用 products 关系,不如在 Order 模型上新建名为 orderProducts 的关系,并用于重复器:

php
use Illuminate\Database\Eloquent\Relations\HasMany;

public function orderProducts(): HasMany
{
    return $this->hasMany(OrderProduct::class);
}

若尚无 OrderProduct pivot 模型,应创建它,并建立到 OrderProduct 的反向关系:

php
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;

class OrderProduct extends Pivot
{
    public $incrementing = true;

    public function order(): BelongsTo
    {
        return $this->belongsTo(Order::class);
    }

    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }
}

INFO

请确保 pivot 模型有主键列(如 id),以便 Filament 跟踪哪些重复器项已创建、更新和删除。为确保 Filament 能跟踪主键,pivot 模型需将 $incrementing 属性设为 true

现在你可以在重复器上使用 orderProducts 关系,数据将保存到 order_product 中间表:

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;

Repeater::make('orderProducts')
    ->relationship()
    ->schema([
        Select::make('product_id')
            ->relationship('product', 'name')
            ->required(),
        // ...
    ])

你可以使用 mutateRelationshipDataBeforeFillUsing() 方法,在相关项数据填充到字段之前对其进行变更。该方法接受一个闭包,通过 $data 变量接收当前项的数据。你必须返回修改后的数据数组:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->relationship()
    ->schema([
        // ...
    ])
    ->mutateRelationshipDataBeforeFillUsing(function (array $data): array {
        $data['user_id'] = auth()->id();

        return $data;
    })

TIP

你可以将各种工具作为参数注入到传递给 mutateRelationshipDataBeforeFillUsing() 的函数中。

你可以使用 mutateRelationshipDataBeforeCreateUsing() 方法,在新相关项写入数据库之前变更其数据。该方法接受一个闭包,通过 $data 变量接收当前项的数据。你可以返回修改后的数据数组,或返回 null 以阻止创建该项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->relationship()
    ->schema([
        // ...
    ])
    ->mutateRelationshipDataBeforeCreateUsing(function (array $data): array {
        $data['user_id'] = auth()->id();

        return $data;
    })

TIP

你可以将各种工具作为参数注入到传递给 mutateRelationshipDataBeforeCreateUsing() 的函数中。

你可以使用 mutateRelationshipDataBeforeSaveUsing() 方法,在已有相关项保存到数据库之前变更其数据。该方法接受一个闭包,通过 $data 变量接收当前项的数据。你可以返回修改后的数据数组,或返回 null 以阻止保存该项:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->relationship()
    ->schema([
        // ...
    ])
    ->mutateRelationshipDataBeforeSaveUsing(function (array $data): array {
        $data['user_id'] = auth()->id();

        return $data;
    })

TIP

你可以将各种工具作为参数注入到传递给 mutateRelationshipDataBeforeSaveUsing() 的函数中。

你可以使用 afterCreate() 方法,在新相关项创建到数据库之后运行代码。该方法接受一个闭包,通过 $data 变量接收当前项数据,通过 $record 变量接收新创建的记录。当你需要记录 ID 以执行附加操作(如关联 pivot 数据)时很有用:

php
use Filament\Forms\Components\Repeater;
use Illuminate\Database\Eloquent\Model;

Repeater::make('variants')
    ->relationship()
    ->schema([
        // ...
    ])
    ->afterCreate(function (array $data, Model $record): void {
        if (isset($data['attributes'])) {
            $record->attributes()->attach($data['attributes']);
        }
    })

TIP

你可以将各种工具作为参数注入到传递给 afterCreate() 的函数中。

你可以使用 afterUpdate() 方法,在已有相关项更新到数据库之后运行代码。该方法接受一个闭包,通过 $data 变量接收当前项数据,通过 $record 变量接收已更新的记录:

php
use Filament\Forms\Components\Repeater;
use Illuminate\Database\Eloquent\Model;

Repeater::make('variants')
    ->relationship()
    ->schema([
        // ...
    ])
    ->afterUpdate(function (array $data, Model $record): void {
        if (isset($data['attributes'])) {
            $record->attributes()->sync($data['attributes']);
        }
    })

TIP

你可以将各种工具作为参数注入到传递给 afterUpdate() 的函数中。

你可以使用 afterDelete() 方法,在相关项从数据库删除之后运行代码。该方法接受一个闭包,通过 $record 变量接收刚删除的记录。此时记录已不在数据库中,但仍可访问其属性(如 ID):

php
use Filament\Forms\Components\Repeater;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;

Repeater::make('attachments')
    ->relationship()
    ->schema([
        // ...
    ])
    ->afterDelete(function (Model $record): void {
        Storage::delete($record->file_path);
    })

TIP

你可以将各种工具作为参数注入到传递给 afterDelete() 的函数中。

你可以使用 modifyRecordsUsing 参数,在从数据库检索后筛选或修改重复器的相关记录。该方法接受一个接收相关记录 Collection 的函数。你应返回修改后的集合。

这在将记录限制到特定分组或类别时尤其有用,且不必在数据库查询本身中完成——若记录已预加载,在查询中过滤会触发额外查询:

php
use Filament\Forms\Components\Repeater;
use Illuminate\Database\Eloquent\Collection;

Repeater::make('startItems')
    ->relationship(name: 'items', modifyRecordsUsing: fn (Collection $records): Collection => $records->where('group', 'start')),
Repeater::make('endItems')
    ->relationship(name: 'items', modifyRecordsUsing: fn (Collection $records): Collection => $records->where('group', 'end')),

TIP

你可以将各种工具作为参数注入到传递给 modifyRecordsUsing 的函数中。

网格布局

你可以使用 grid() 方法将重复器项组织为多列:

php
use Filament\Forms\Components\Repeater;

Repeater::make('qualifications')
    ->schema([
        // ...
    ])
    ->grid(2)
项为两列网格的重复器项为两列网格的重复器

该方法接受与 网格columns() 方法相同的选项。这允许你在不同断点响应式地自定义网格列数。

TIP

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

根据内容为重复器项添加标签

你可以使用 itemLabel() 方法为重复器项添加标签。该方法接受一个闭包,通过 $state 变量接收当前项的数据。你必须返回用作项标签的字符串:

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;

Repeater::make('members')
    ->schema([
        TextInput::make('name')
            ->required()
            ->live(onBlur: true),
        Select::make('role')
            ->options([
                'member' => 'Member',
                'administrator' => 'Administrator',
                'owner' => 'Owner',
            ])
            ->required(),
    ])
    ->columns(2)
    ->itemLabel(fn (array $state): ?string => $state['name'] ?? null),

TIP

若希望在使用表单时实时更新项标签,从 $state 使用的任何字段都应设为 live()

TIP

你可以将各种工具作为参数注入到传递给 itemLabel() 的函数中。

带项标签的重复器带项标签的重复器

为重复器项编号

你可以使用 itemNumbers() 方法在项标签旁添加重复器项编号:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->itemNumbers()
带编号项的重复器带编号项的重复器

单字段简易重复器

你可以使用 simple() 方法创建仅含单个字段、采用精简设计的重复器

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;

Repeater::make('invitations')
    ->simple(
        TextInput::make('email')
            ->email()
            ->required(),
    )

TIP

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

仅含一个字段的简易重复器设计仅含一个字段的简易重复器设计

简易重复器使用扁平值数组而非嵌套数组存储数据。这意味着上例的数据结构可能如下:

php
[
    'invitations' => [
        'dan@filamentphp.com',
        'ryan@filamentphp.com',
    ],
],

使用 $get() 访问父级字段值

所有表单组件都能 使用 $get()$set() 访问另一字段的值。但在重复器的 schema 内使用时,可能会遇到意外行为。

因为 $get()$set() 默认作用域为当前重复器项。这意味着你可以轻松与该重复器项内的另一字段交互,而无需知道当前表单组件属于哪一项。

其后果是,当你无法与重复器外的字段交互时可能会感到困惑。我们使用 ../ 语法解决此问题——$get('../parent_field_name')

假设你的表单有如下数据结构:

php
[
    'client_id' => 1,

    'repeater' => [
        'item1' => [
            'service_id' => 2,
        ],
    ],
]

你正尝试从重复器项内部检索 client_id 的值。

$get() 相对于当前重复器项,因此 $get('client_id') 实际在查找 $get('repeater.item1.client_id')

你可以使用 ../ 在数据结构中上移一层,因此 $get('../client_id')$get('repeater.client_id'),而 $get('../../client_id')$get('client_id')

无参的 $get(),或 $get('') / $get('./') 这一特殊情况,将始终返回当前重复器项的完整数据数组。

表格重复器

你可以使用 table() 方法以表格形式呈现重复器项,该方法接受 TableColumn 对象数组。这些对象表示表格的列,对应重复器 schema 中的各个组件:

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Repeater\TableColumn;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;

Repeater::make('members')
    ->table([
        TableColumn::make('Name'),
        TableColumn::make('Role'),
    ])
    ->schema([
        TextInput::make('name')
            ->required(),
        Select::make('role')
            ->options([
                'member' => 'Member',
                'administrator' => 'Administrator',
                'owner' => 'Owner',
            ])
            ->required(),
    ])
表格布局的重复器表格布局的重复器

表头中显示的标签会传给 TableColumn::make() 方法。若希望为列提供无访问标签但不显示,可使用 hiddenHeaderLabel() 方法:

php
use Filament\Forms\Components\Repeater\TableColumn;

TableColumn::make('Name')
    ->hiddenHeaderLabel()

若希望用红色星号将列标记为「必填」,可使用 markAsRequired() 方法:

php
use Filament\Forms\Components\Repeater\TableColumn;

TableColumn::make('Name')
    ->markAsRequired()

你可以使用 wrapHeader() 方法启用列标题换行:

php
use Filament\Forms\Components\Repeater\TableColumn;

TableColumn::make('Name')
    ->wrapHeader()

你也可以使用 alignment() 方法调整列标题对齐方式,传入 Alignment::StartAlignment::CenterAlignment::End

php
use Filament\Forms\Components\Repeater\TableColumn;
use Filament\Support\Enums\Alignment;

TableColumn::make('Name')
    ->alignment(Alignment::Start)

你可以使用 width() 方法设置固定列宽,传入表示列宽的字符串。该值会直接传给列标题的 style 属性:

php
use Filament\Forms\Components\Repeater\TableColumn;

TableColumn::make('Name')
    ->width('200px')

紧凑表格重复器

你可以使用 compact() 方法让表格重复器更紧凑,以便在更小空间中容纳更多数据:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->table([
        // ...
    ])
    ->compact()
    ->schema([
        // ...
    ])

你也可以传入布尔值,以控制表格重复器是否紧凑:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->table([
        // ...
    ])
    ->compact(FeatureFlag::active())
    ->schema([
        // ...
    ])

TIP

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

紧凑表格布局的重复器紧凑表格布局的重复器

重复器校验

除了 校验 页面列出的全部规则外,还有专门针对重复器的额外规则。

项数量校验

你可以通过设置 minItems()maxItems() 方法校验重复器中可有的最小与最大项数:

php
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->minItems(2)
    ->maxItems(5)

TIP

除了允许静态值外,minItems()maxItems() 方法也接受函数以动态计算。你可以将各种工具作为参数注入到这些函数中。

互斥状态校验

在许多情况下,你希望确保重复器项之间具有某种唯一性。几个常见例子包括:

  • 确保重复器各项中同一时间只有一个 [复选框](/5.x/forms/checkbox) 或 [开关](/5.x/forms/toggle) 被激活。
  • 确保某个选项在重复器中的 [选择框](/5.x/forms/select)、[单选](/5.x/forms/radio)、[复选框列表](/5.x/forms/checkbox-list) 或 [切换按钮](/5.x/forms/toggle-buttons) 字段中只能被选择一次。

你可以使用 distinct() 方法校验某字段状态在重复器所有项中唯一:

php
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Repeater;

Repeater::make('answers')
    ->schema([
        // ...
        Checkbox::make('is_correct')
            ->distinct(),
    ])

distinct() 校验的行为取决于字段处理的数据类型

  • 若字段返回布尔值,如 [复选框](/5.x/forms/checkbox) 或 [开关](/5.x/forms/toggle),校验将确保只有一项的值为 `true`。重复器中可以有许多字段值为 `false`。
  • 否则,对于 [选择框](/5.x/forms/select)、[单选](/5.x/forms/radio)、[复选框列表](/5.x/forms/checkbox-list) 或 [切换按钮](/5.x/forms/toggle-buttons) 等字段,校验将确保每个选项在重复器所有项中只能被选择一次。

你也可以向 distinct() 方法传入布尔值,以控制字段是否应互斥:

php
use Filament\Forms\Components\Checkbox;

Checkbox::make('is_correct')
    ->distinct(FeatureFlag::active())

TIP

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

自动修复非互斥状态

若希望自动修复非互斥状态,可使用 fixIndistinctState() 方法:

php
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Repeater;

Repeater::make('answers')
    ->schema([
        // ...
        Checkbox::make('is_correct')
            ->fixIndistinctState(),
    ])

此方法会自动在字段上启用 distinct()live()

根据字段处理的数据类型,fixIndistinctState() 的行为会相应调整:

  • 若字段返回布尔值,如 [复选框](/5.x/forms/checkbox) 或 [开关](/5.x/forms/toggle),且其中一个字段被启用,Filament 会代表用户自动禁用所有其他已启用的字段。
  • 否则,对于 [选择框](/5.x/forms/select)、[单选](/5.x/forms/radio)、[复选框列表](/5.x/forms/checkbox-list) 或 [切换按钮](/5.x/forms/toggle-buttons) 等字段,当用户选择某个选项时,Filament 会代表用户自动取消该选项在其他位置的选择。

你也可以向 fixIndistinctState() 方法传入布尔值,以控制字段是否应修复非互斥状态:

php
use Filament\Forms\Components\Checkbox;

Checkbox::make('is_correct')
    ->fixIndistinctState(FeatureFlag::active())

TIP

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

在其他项已选时禁用选项

若希望在 选择框单选复选框列表切换按钮 中,当选项已在其他项中被选中时将其禁用,可使用 disableOptionsWhenSelectedInSiblingRepeaterItems() 方法:

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;

Repeater::make('members')
    ->schema([
        Select::make('role')
            ->options([
                // ...
            ])
            ->disableOptionsWhenSelectedInSiblingRepeaterItems(),
    ])

此方法会自动在字段上启用 distinct()live()

WARNING

若还想添加其他 禁用选项 的条件,可以链式调用带 merge: true 参数的 disableOptionWhen()

php
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
    
Repeater::make('members')
    ->schema([
        Select::make('role')
            ->options([
                // ...
            ])
            ->disableOptionsWhenSelectedInSiblingRepeaterItems()
            ->disableOptionWhen(fn (string $value): bool => $value === 'super_admin', merge: true),
    ])

自定义重复器项操作

此字段使用 action 对象,便于自定义其中的按钮。你可以通过向操作注册方法传入函数来自定义这些按钮。该函数可访问 $action 对象,用于 自定义它。以下方法可用于自定义操作:

  • addAction()
  • cloneAction()
  • collapseAction()
  • collapseAllAction()
  • deleteAction()
  • expandAction()
  • expandAllAction()
  • moveDownAction()
  • moveUpAction()
  • reorderAction()

以下是自定义操作的示例:

php
use Filament\Actions\Action;
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->collapseAllAction(
        fn (Action $action) => $action->label('Collapse all members'),
    )

TIP

操作注册方法可以将各种工具作为参数注入到函数中。

用模态确认重复器操作

你可以通过在 action 对象上使用 requiresConfirmation() 方法,用模态确认操作。你可以使用任意 模态自定义方法 更改其内容与行为:

php
use Filament\Actions\Action;
use Filament\Forms\Components\Repeater;

Repeater::make('members')
    ->schema([
        // ...
    ])
    ->deleteAction(
        fn (Action $action) => $action->requiresConfirmation(),
    )

INFO

collapseAction()collapseAllAction()expandAction()expandAllAction()reorderAction() 方法不支持确认模态,因为点击其按钮不会发起显示模态所需的网络请求。

向重复器添加额外项操作

你可以通过将 Action 对象传入 extraItemActions(),在每个重复器项的标题栏添加新的 操作按钮

php
use Filament\Actions\Action;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\Facades\Mail;

Repeater::make('members')
    ->schema([
        TextInput::make('email')
            ->label('Email address')
            ->email(),
        // ...
    ])
    ->extraItemActions([
        Action::make('sendEmail')
            ->icon(Heroicon::Envelope)
            ->action(function (array $arguments, Repeater $component): void {
                $itemData = $component->getItemState($arguments['item']);

                Mail::to($itemData['email'])
                    ->send(
                        // ...
                    );
            }),
    ])

在此示例中,$arguments['item'] 给出当前重复器项的 ID。你可以使用重复器组件上的 getItemState() 方法校验该重复器项中的数据。该方法返回该项的已校验数据。若该项无效,将取消操作并在表单中为该项显示错误消息。

若希望获取当前项的原始数据而不校验,可改用 $component->getRawItemState($arguments['item'])

若希望操作整个重复器的原始数据,例如添加、移除或修改项,可以使用 $component->getState() 获取数据,再用 $component->state($state) 重新设置:

php
use Illuminate\Support\Str;

// Get the raw data for the entire repeater
$state = $component->getState();

// Add an item, with a random UUID as the key
$state[Str::uuid()] = [
    'email' => auth()->user()->email,
];

// Set the new data for the repeater
$component->state($state);