mirror of
https://github.com/filamentphp/filament.git
synced 2026-10-16 07:17:49 +08:00
repeater and builder docs and uuid/key consistency
This commit is contained in:
@@ -90,21 +90,21 @@
|
||||
$hasBlockNumbers = $hasBlockNumbers();
|
||||
@endphp
|
||||
|
||||
@foreach ($items as $uuid => $item)
|
||||
@foreach ($items as $itemKey => $item)
|
||||
@php
|
||||
$visibleExtraItemActions = array_filter(
|
||||
$extraItemActions,
|
||||
fn (Action $action): bool => $action(['item' => $uuid])->isVisible(),
|
||||
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
|
||||
);
|
||||
$cloneAction = $cloneAction(['item' => $uuid]);
|
||||
$cloneAction = $cloneAction(['item' => $itemKey]);
|
||||
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
|
||||
$deleteAction = $deleteAction(['item' => $uuid]);
|
||||
$deleteAction = $deleteAction(['item' => $itemKey]);
|
||||
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
|
||||
$editAction = $editAction(['item' => $uuid]);
|
||||
$editAction = $editAction(['item' => $itemKey]);
|
||||
$editActionIsVisible = $hasBlockPreviews && $editAction->isVisible();
|
||||
$moveDownAction = $moveDownAction(['item' => $uuid])->disabled($loop->last);
|
||||
$moveDownAction = $moveDownAction(['item' => $itemKey])->disabled($loop->last);
|
||||
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
|
||||
$moveUpAction = $moveUpAction(['item' => $uuid])->disabled($loop->first);
|
||||
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
|
||||
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
|
||||
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
|
||||
@endphp
|
||||
@@ -117,7 +117,7 @@
|
||||
x-on:builder-expand.window="$event.detail === '{{ $statePath }}' && (isCollapsed = false)"
|
||||
x-on:builder-collapse.window="$event.detail === '{{ $statePath }}' && (isCollapsed = true)"
|
||||
x-on:expand="isCollapsed = false"
|
||||
x-sortable-item="{{ $uuid }}"
|
||||
x-sortable-item="{{ $itemKey }}"
|
||||
class="fi-fo-builder-item"
|
||||
x-bind:class="{ 'fi-collapsed': isCollapsed }"
|
||||
>
|
||||
@@ -154,7 +154,7 @@
|
||||
@endif
|
||||
|
||||
@php
|
||||
$blockIcon = $item->getParentComponent()->getIcon($item->getRawState(), $uuid);
|
||||
$blockIcon = $item->getParentComponent()->getIcon($item->getRawState(), $itemKey);
|
||||
@endphp
|
||||
|
||||
@if ($hasBlockIcons && filled($blockIcon))
|
||||
@@ -168,7 +168,7 @@
|
||||
'fi-truncated' => $isBlockLabelTruncated,
|
||||
])
|
||||
>
|
||||
{{ $item->getParentComponent()->getLabel($item->getRawState(), $uuid) }}
|
||||
{{ $item->getParentComponent()->getLabel($item->getRawState(), $itemKey) }}
|
||||
|
||||
@if ($hasBlockNumbers)
|
||||
{{ $loop->iteration }}
|
||||
@@ -182,7 +182,7 @@
|
||||
>
|
||||
@foreach ($visibleExtraItemActions as $extraItemAction)
|
||||
<li x-on:click.stop>
|
||||
{{ $extraItemAction(['item' => $uuid]) }}
|
||||
{{ $extraItemAction(['item' => $itemKey]) }}
|
||||
</li>
|
||||
@endforeach
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
<div
|
||||
class="fi-fo-builder-item-preview-edit-overlay"
|
||||
role="button"
|
||||
x-on:click.stop="{{ '$wire.mountFormComponentAction(\'' . $statePath . '\', \'edit\', { item: \'' . $uuid . '\' })' }}"
|
||||
x-on:click.stop="{{ '$wire.mountFormComponentAction(\'' . $statePath . '\', \'edit\', { item: \'' . $itemKey . '\' })' }}"
|
||||
></div>
|
||||
@endif
|
||||
@else
|
||||
@@ -258,20 +258,20 @@
|
||||
</li>
|
||||
|
||||
@if (! $loop->last)
|
||||
@if ($isAddable && $addBetweenAction(['afterItem' => $uuid])->isVisible())
|
||||
@if ($isAddable && $addBetweenAction(['afterItem' => $itemKey])->isVisible())
|
||||
<li class="fi-fo-builder-add-between-items-ctn">
|
||||
<div class="fi-fo-builder-add-between-items">
|
||||
<div class="fi-fo-builder-block-picker-ctn">
|
||||
<x-filament-forms::builder.block-picker
|
||||
:action="$addBetweenAction"
|
||||
:after-item="$uuid"
|
||||
:after-item="$itemKey"
|
||||
:columns="$blockPickerColumns"
|
||||
:blocks="$blockPickerBlocks"
|
||||
:key="$key"
|
||||
:width="$blockPickerWidth"
|
||||
>
|
||||
<x-slot name="trigger">
|
||||
{{ $addBetweenAction(['afterItem' => $uuid]) }}
|
||||
{{ $addBetweenAction(['afterItem' => $itemKey]) }}
|
||||
</x-slot>
|
||||
</x-filament-forms::builder.block-picker>
|
||||
</div>
|
||||
|
||||
@@ -86,20 +86,20 @@
|
||||
->class(['fi-fo-repeater-items'])
|
||||
}}
|
||||
>
|
||||
@foreach ($items as $uuid => $item)
|
||||
@foreach ($items as $itemKey => $item)
|
||||
@php
|
||||
$itemLabel = $getItemLabel($uuid);
|
||||
$itemLabel = $getItemLabel($itemKey);
|
||||
$visibleExtraItemActions = array_filter(
|
||||
$extraItemActions,
|
||||
fn (Action $action): bool => $action(['item' => $uuid])->isVisible(),
|
||||
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
|
||||
);
|
||||
$cloneAction = $cloneAction(['item' => $uuid]);
|
||||
$cloneAction = $cloneAction(['item' => $itemKey]);
|
||||
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
|
||||
$deleteAction = $deleteAction(['item' => $uuid]);
|
||||
$deleteAction = $deleteAction(['item' => $itemKey]);
|
||||
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
|
||||
$moveDownAction = $moveDownAction(['item' => $uuid])->disabled($loop->last);
|
||||
$moveDownAction = $moveDownAction(['item' => $itemKey])->disabled($loop->last);
|
||||
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
|
||||
$moveUpAction = $moveUpAction(['item' => $uuid])->disabled($loop->first);
|
||||
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
|
||||
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
|
||||
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
|
||||
@endphp
|
||||
@@ -112,7 +112,7 @@
|
||||
x-on:repeater-expand.window="$event.detail === '{{ $statePath }}' && (isCollapsed = false)"
|
||||
x-on:repeater-collapse.window="$event.detail === '{{ $statePath }}' && (isCollapsed = true)"
|
||||
x-on:expand="isCollapsed = false"
|
||||
x-sortable-item="{{ $uuid }}"
|
||||
x-sortable-item="{{ $itemKey }}"
|
||||
class="fi-fo-repeater-item"
|
||||
x-bind:class="{ 'fi-collapsed': isCollapsed }"
|
||||
>
|
||||
@@ -165,7 +165,7 @@
|
||||
>
|
||||
@foreach ($visibleExtraItemActions as $extraItemAction)
|
||||
<li x-on:click.stop>
|
||||
{{ $extraItemAction(['item' => $uuid]) }}
|
||||
{{ $extraItemAction(['item' => $itemKey]) }}
|
||||
</li>
|
||||
@endforeach
|
||||
|
||||
@@ -213,10 +213,10 @@
|
||||
</li>
|
||||
|
||||
@if (! $loop->last)
|
||||
@if ($isAddable && $addBetweenAction(['afterItem' => $uuid])->isVisible())
|
||||
@if ($isAddable && $addBetweenAction(['afterItem' => $itemKey])->isVisible())
|
||||
<li class="fi-fo-repeater-add-between-items-ctn">
|
||||
<div class="fi-fo-repeater-add-between-items">
|
||||
{{ $addBetweenAction(['afterItem' => $uuid]) }}
|
||||
{{ $addBetweenAction(['afterItem' => $itemKey]) }}
|
||||
</div>
|
||||
</li>
|
||||
@elseif (filled($labelBetweenItems))
|
||||
|
||||
@@ -47,26 +47,26 @@
|
||||
->class(['fi-fo-repeater-items'])
|
||||
}}
|
||||
>
|
||||
@foreach ($items as $uuid => $item)
|
||||
@foreach ($items as $itemKey => $item)
|
||||
@php
|
||||
$visibleExtraItemActions = array_filter(
|
||||
$extraItemActions,
|
||||
fn (Action $action): bool => $action(['item' => $uuid])->isVisible(),
|
||||
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
|
||||
);
|
||||
$cloneAction = $cloneAction(['item' => $uuid]);
|
||||
$cloneAction = $cloneAction(['item' => $itemKey]);
|
||||
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
|
||||
$deleteAction = $deleteAction(['item' => $uuid]);
|
||||
$deleteAction = $deleteAction(['item' => $itemKey]);
|
||||
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
|
||||
$moveDownAction = $moveDownAction(['item' => $uuid])->disabled($loop->last);
|
||||
$moveDownAction = $moveDownAction(['item' => $itemKey])->disabled($loop->last);
|
||||
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
|
||||
$moveUpAction = $moveUpAction(['item' => $uuid])->disabled($loop->first);
|
||||
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
|
||||
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
|
||||
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
|
||||
@endphp
|
||||
|
||||
<li
|
||||
wire:key="{{ $item->getLivewireKey() }}.item"
|
||||
x-sortable-item="{{ $uuid }}"
|
||||
x-sortable-item="{{ $itemKey }}"
|
||||
class="fi-fo-repeater-item"
|
||||
>
|
||||
<div class="fi-fo-repeater-item-content">
|
||||
@@ -93,7 +93,7 @@
|
||||
|
||||
@foreach ($visibleExtraItemActions as $extraItemAction)
|
||||
<li x-on:click.stop>
|
||||
{{ $extraItemAction(['item' => $uuid]) }}
|
||||
{{ $extraItemAction(['item' => $itemKey]) }}
|
||||
</li>
|
||||
@endforeach
|
||||
|
||||
|
||||
@@ -106,8 +106,8 @@ class Builder extends Field implements CanConcealComponents, HasExtraItemActions
|
||||
$items = [];
|
||||
|
||||
foreach ($state ?? [] as $itemData) {
|
||||
if ($uuid = $component->generateUuid()) {
|
||||
$items[$uuid] = $itemData;
|
||||
if ($key = $component->generateUuid()) {
|
||||
$items[$key] = $itemData;
|
||||
} else {
|
||||
$items[] = $itemData;
|
||||
}
|
||||
@@ -1123,17 +1123,17 @@ class Builder extends Field implements CanConcealComponents, HasExtraItemActions
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getItemState(string $uuid): array
|
||||
public function getItemState(string $key): array
|
||||
{
|
||||
return $this->getChildSchema($uuid)->getState(shouldCallHooksBefore: false);
|
||||
return $this->getChildSchema($key)->getState(shouldCallHooksBefore: false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getRawItemState(string $uuid): array
|
||||
public function getRawItemState(string $key): array
|
||||
{
|
||||
return $this->getChildSchema($uuid)->getRawState();
|
||||
return $this->getChildSchema($key)->getRawState();
|
||||
}
|
||||
|
||||
public function getHeadingsCount(): int
|
||||
|
||||
@@ -73,11 +73,11 @@ class Block extends Component
|
||||
/**
|
||||
* @param array<string, mixed> | null $state
|
||||
*/
|
||||
public function getLabel(?array $state = null, ?string $uuid = null): string | Htmlable
|
||||
public function getLabel(?array $state = null, ?string $key = null): string | Htmlable
|
||||
{
|
||||
return $this->evaluate(
|
||||
$this->label,
|
||||
['state' => $state, 'uuid' => $uuid],
|
||||
['key' => $key, 'state' => $state, 'uuid' => $key],
|
||||
) ?? $this->getDefaultLabel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,8 +135,8 @@ class Repeater extends Field implements CanConcealComponents, HasExtraItemAction
|
||||
$itemData = [$simpleField->getName() => $itemData];
|
||||
}
|
||||
|
||||
if ($uuid = $component->generateUuid()) {
|
||||
$items[$uuid] = $itemData;
|
||||
if ($key = $component->generateUuid()) {
|
||||
$items[$key] = $itemData;
|
||||
} else {
|
||||
$items[] = $itemData;
|
||||
}
|
||||
@@ -710,8 +710,8 @@ class Repeater extends Field implements CanConcealComponents, HasExtraItemAction
|
||||
$itemData = [$simpleField->getName() => $itemData];
|
||||
}
|
||||
|
||||
if ($uuid = $component->generateUuid()) {
|
||||
$items[$uuid] = $itemData;
|
||||
if ($key = $component->generateUuid()) {
|
||||
$items[$key] = $itemData;
|
||||
} else {
|
||||
$items[] = $itemData;
|
||||
}
|
||||
@@ -1146,15 +1146,17 @@ class Repeater extends Field implements CanConcealComponents, HasExtraItemAction
|
||||
);
|
||||
}
|
||||
|
||||
public function getItemLabel(string $uuid): string | Htmlable | null
|
||||
public function getItemLabel(string $key): string | Htmlable | null
|
||||
{
|
||||
$container = $this->getChildSchema($uuid);
|
||||
$container = $this->getChildSchema($key);
|
||||
|
||||
return $this->evaluate($this->itemLabel, [
|
||||
'container' => $container,
|
||||
'item' => $container,
|
||||
'key' => $key,
|
||||
'schema' => $container,
|
||||
'state' => $container->getRawState(),
|
||||
'uuid' => $uuid,
|
||||
'uuid' => $key,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1303,17 +1305,17 @@ class Repeater extends Field implements CanConcealComponents, HasExtraItemAction
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getItemState(string $uuid): array
|
||||
public function getItemState(string $key): array
|
||||
{
|
||||
return $this->getChildSchema($uuid)->getState(shouldCallHooksBefore: false);
|
||||
return $this->getChildSchema($key)->getState(shouldCallHooksBefore: false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getRawItemState(string $uuid): array
|
||||
public function getRawItemState(string $key): array
|
||||
{
|
||||
return $this->getChildSchema($uuid)->getRawState();
|
||||
return $this->getChildSchema($key)->getRawState();
|
||||
}
|
||||
|
||||
public function getHeadingsCount(): int
|
||||
|
||||
@@ -332,6 +332,8 @@ Repeater::make('qualifications')
|
||||
->orderColumn('order_column')
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `orderColumn()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Integrating with a `BelongsToMany` Eloquent relationship
|
||||
|
||||
There is a common misconception that using a `BelongsToMany` relationship with a repeater is as simple as using a `HasMany` relationship. This is not the case, as a `BelongsToMany` relationship requires a pivot table to store the relationship data. The repeater saves its data to the related model, not the pivot table. Therefore, if you want to map each repeater item to a row in the pivot table, you must use a `HasMany` relationship with a pivot model to use a repeater with a `BelongsToMany` relationship.
|
||||
@@ -369,7 +371,9 @@ class OrderProduct extends Pivot
|
||||
}
|
||||
```
|
||||
|
||||
> Please ensure that your pivot model has a primary key column, like `id`, to allow Filament to keep track of which repeater items have been created, updated and deleted. To make sure that Filament keeps track of the primary key, the pivot model needs to have the `$incrementing` property set to `true`.
|
||||
<Aside variant="info">
|
||||
Please ensure that your pivot model has a primary key column, like `id`, to allow Filament to keep track of which repeater items have been created, updated and deleted. To make sure that Filament keeps track of the primary key, the pivot model needs to have the `$incrementing` property set to `true`.
|
||||
</Aside>
|
||||
|
||||
Now you can use the `orderProducts` relationship with the repeater, and it will save the data to the `order_product` pivot table:
|
||||
|
||||
@@ -406,6 +410,8 @@ Repeater::make('qualifications')
|
||||
})
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x" extras="Data;;array<array<string, mixed>>;;$data;;The data that is being filled into the repeater.">You can inject various utilities into the function passed to `mutateRelationshipDataBeforeFillUsing()` as parameters.</UtilityInjection>
|
||||
|
||||
### Mutating related item data before creating
|
||||
|
||||
You may mutate the data for a new related item before it is created in the database using the `mutateRelationshipDataBeforeCreateUsing()` method. This method accepts a closure that receives the current item's data in a `$data` variable. You can choose to return either the modified array of data, or `null` to prevent the item from being created:
|
||||
@@ -425,6 +431,8 @@ Repeater::make('qualifications')
|
||||
})
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x" extras="Data;;array<string, mixed>;;$data;;The data that is being saved by the repeater.">You can inject various utilities into the function passed to `mutateRelationshipDataBeforeCreateUsing()` as parameters.</UtilityInjection>
|
||||
|
||||
### Mutating related item data before saving
|
||||
|
||||
You may mutate the data for an existing related item before it is saved in the database using the `mutateRelationshipDataBeforeSaveUsing()` method. This method accepts a closure that receives the current item's data in a `$data` variable. You can choose to return either the modified array of data, or `null` to prevent the item from being saved:
|
||||
@@ -444,6 +452,8 @@ Repeater::make('qualifications')
|
||||
})
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x" extras="Data;;array<string, mixed>;;$data;;The data that is being saved by the repeater.">You can inject various utilities into the function passed to `mutateRelationshipDataBeforeSaveUsing()` as parameters.</UtilityInjection>
|
||||
|
||||
## Grid layout
|
||||
|
||||
You may organize repeater items into columns by using the `grid()` method:
|
||||
@@ -460,7 +470,9 @@ Repeater::make('qualifications')
|
||||
|
||||
<AutoScreenshot name="forms/fields/repeater/grid" alt="Repeater with a 2 column grid of items" version="4.x" />
|
||||
|
||||
This method accepts the same options as the `columns()` method of the [grid](../../schemas/layouts/grid). This allows you to responsively customize the number of grid columns at various breakpoints.
|
||||
This method accepts the same options as the `columns()` method of the [grid](../layouts/grid). This allows you to responsively customize the number of grid columns at various breakpoints.
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `grid()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Adding a label to repeater items based on their content
|
||||
|
||||
@@ -488,7 +500,11 @@ Repeater::make('members')
|
||||
->itemLabel(fn (array $state): ?string => $state['name'] ?? null),
|
||||
```
|
||||
|
||||
Any fields that you use from `$state` should be `live()` if you wish to see the item label update live as you use the form.
|
||||
<Aside variant="tip">
|
||||
Any fields that you use from `$state` should be `live()` if you wish to see the item label update live as you use the form.
|
||||
</Aside>
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x" extras="Item;;Filament\Schemas\Schema;;$item;;The schema object for the current repeater item.||Key;;string;;$key;;The key for the current repeater item.||State;;array<string, mixed>;;$state;;The raw unvalidated data for the current repeater item.">You can inject various utilities into the function passed to `itemLabel()` as parameters.</UtilityInjection>
|
||||
|
||||
<AutoScreenshot name="forms/fields/repeater/labelled" alt="Repeater with item labels" version="4.x" />
|
||||
|
||||
@@ -508,6 +524,8 @@ Repeater::make('invitations')
|
||||
)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `simple()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
<AutoScreenshot name="forms/fields/repeater/simple-one-field" alt="Simple repeater design with only one field" version="4.x" />
|
||||
|
||||
Instead of using a nested array to store data, simple repeaters use a flat array of values. This means that the data structure for the above example could look like this:
|
||||
@@ -523,7 +541,7 @@ Instead of using a nested array to store data, simple repeaters use a flat array
|
||||
|
||||
## Using `$get()` to access parent field values
|
||||
|
||||
All form components are able to [use `$get()` and `$set()`](../advanced) to access another field's value. However, you might experience unexpected behavior when using this inside the repeater's schema.
|
||||
All form components are able to [use `$get()` and `$set()`](overview#injecting-the-state-of-another-field) to access another field's value. However, you might experience unexpected behavior when using this inside the repeater's schema.
|
||||
|
||||
This is because `$get()` and `$set()`, by default, are scoped to the current repeater item. This means that you are able to interact with another field inside that repeater item easily without knowing which repeater item the current form component belongs to.
|
||||
|
||||
@@ -570,6 +588,8 @@ Repeater::make('members')
|
||||
->maxItems(5)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing static values, the `minItems()` and `maxItems()` methods also accept a function to dynamically calculate them. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Distinct state validation
|
||||
|
||||
In many cases, you will want to ensure some sort of uniqueness between repeater items. A couple of common examples could be:
|
||||
@@ -596,6 +616,17 @@ The behavior of the `distinct()` validation depends on the data type that the fi
|
||||
- If the field returns a boolean, like a [checkbox](checkbox) or [toggle](toggle), the validation will ensure that only one item has a value of `true`. There may be many fields in the repeater that have a value of `false`.
|
||||
- Otherwise, for fields like a [select](select), [radio](radio), [checkbox list](checkbox-list), or [toggle buttons](toggle-buttons), the validation will ensure that each option may only be selected once across all items in the repeater.
|
||||
|
||||
Optionally, you may pass a boolean value to the `distinct()` method to control if the field should be distinct or not:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
|
||||
Checkbox::make('is_correct')
|
||||
->distinct(FeatureFlag::active())
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `distinct()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
#### Automatically fixing indistinct state
|
||||
|
||||
If you'd like to automatically fix indistinct state, you can use the `fixIndistinctState()` method:
|
||||
@@ -619,6 +650,17 @@ Depending on the data type that the field handles, the behavior of the `fixIndis
|
||||
- If the field returns a boolean, like a [checkbox](checkbox) or [toggle](toggle), and one of the fields is enabled, Filament will automatically disable all other enabled fields on behalf of the user.
|
||||
- Otherwise, for fields like a [select](select), [radio](radio), [checkbox list](checkbox-list), or [toggle buttons](toggle-buttons), when a user selects an option, Filament will automatically deselect all other usages of that option on behalf of the user.
|
||||
|
||||
Optionally, you may pass a boolean value to the `fixIndistinctState()` method to control if the field should fix indistinct state or not:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
|
||||
Checkbox::make('is_correct')
|
||||
->fixIndistinctState(FeatureFlag::active())
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `fixIndistinctState()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
#### Disabling options when they are already selected in another item
|
||||
|
||||
If you'd like to disable options in a [select](select), [radio](radio), [checkbox list](checkbox-list), or [toggle buttons](toggle-buttons) when they are already selected in another item, you can use the `disableOptionsWhenSelectedInSiblingRepeaterItems()` method:
|
||||
@@ -639,22 +681,24 @@ Repeater::make('members')
|
||||
|
||||
This method will automatically enable the `distinct()` and `live()` methods on the field.
|
||||
|
||||
In case you want to add another condition to [disable options](../select#disabling-specific-options) with, you can chain `disableOptionWhen()` with the `merge: true` argument:
|
||||
|
||||
```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),
|
||||
])
|
||||
```
|
||||
<Aside variant="warning">
|
||||
In case you want to add another condition to [disable options](../select#disabling-specific-options) with, you can chain `disableOptionWhen()` with the `merge: true` argument:
|
||||
|
||||
```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),
|
||||
])
|
||||
```
|
||||
</Aside>
|
||||
|
||||
## Customizing the repeater item actions
|
||||
|
||||
@@ -686,6 +730,8 @@ Repeater::make('members')
|
||||
)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x" extras="Action;;Filament\Actions\Action;;$action;;The action object to customize.">The action registration methods can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Confirming repeater actions with a modal
|
||||
|
||||
You can confirm actions with a modal by using the `requiresConfirmation()` method on the action object. You may use any [modal customization method](../../actions/modals) to change its content and behavior:
|
||||
@@ -703,11 +749,13 @@ Repeater::make('members')
|
||||
)
|
||||
```
|
||||
|
||||
> The `collapseAction()`, `collapseAllAction()`, `expandAction()`, `expandAllAction()` and `reorderAction()` methods do not support confirmation modals, as clicking their buttons does not make the network request that is required to show the modal.
|
||||
<Aside variant="info">
|
||||
The `collapseAction()`, `collapseAllAction()`, `expandAction()`, `expandAllAction()` and `reorderAction()` methods do not support confirmation modals, as clicking their buttons does not make the network request that is required to show the modal.
|
||||
</Aside>
|
||||
|
||||
### Adding extra item actions to a repeater
|
||||
|
||||
You may add new [action buttons](../../schemas/actions) to the header of each repeater item by passing `Action` objects into `extraItemActions()`:
|
||||
You may add new [action buttons](../primes/actions-in-schemas) to the header of each repeater item by passing `Action` objects into `extraItemActions()`:
|
||||
|
||||
```php
|
||||
use Filament\Actions\Action;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Builder
|
||||
---
|
||||
import Aside from "@components/Aside.astro"
|
||||
import AutoScreenshot from "@components/AutoScreenshot.astro"
|
||||
import UtilityInjection from "@components/UtilityInjection.astro"
|
||||
|
||||
@@ -12,6 +13,7 @@ The primary use of the builder component is to build web page content using pred
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
@@ -19,7 +21,7 @@ use Filament\Forms\Components\TextInput;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
Builder\Block::make('heading')
|
||||
Block::make('heading')
|
||||
->schema([
|
||||
TextInput::make('content')
|
||||
->label('Heading')
|
||||
@@ -36,13 +38,13 @@ Builder::make('content')
|
||||
->required(),
|
||||
])
|
||||
->columns(2),
|
||||
Builder\Block::make('paragraph')
|
||||
Block::make('paragraph')
|
||||
->schema([
|
||||
Textarea::make('content')
|
||||
->label('Paragraph')
|
||||
->required(),
|
||||
]),
|
||||
Builder\Block::make('image')
|
||||
Block::make('image')
|
||||
->schema([
|
||||
FileUpload::make('url')
|
||||
->label('Image')
|
||||
@@ -63,11 +65,12 @@ As evident in the above example, blocks can be defined within the `blocks()` met
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
Builder\Block::make('heading')
|
||||
Block::make('heading')
|
||||
->schema([
|
||||
TextInput::make('content')->required(),
|
||||
// ...
|
||||
@@ -81,9 +84,9 @@ Builder::make('content')
|
||||
By default, the label of the block will be automatically determined based on its name. To override the block's label, you may use the `label()` method. Customizing the label in this way is useful if you wish to use a [translation string for localization](https://laravel.com/docs/localization#retrieving-translation-strings):
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
|
||||
Builder\Block::make('heading')
|
||||
Block::make('heading')
|
||||
->label(__('blocks.heading'))
|
||||
```
|
||||
|
||||
@@ -92,10 +95,10 @@ Builder\Block::make('heading')
|
||||
You may add a label for a builder item using the same `label()` method. This method accepts a closure that receives the item's data in a `$state` variable. If `$state` is null, you should return the block label that should be displayed in the block picker. Otherwise, you should return a string to be used as the item label:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
|
||||
Builder\Block::make('heading')
|
||||
Block::make('heading')
|
||||
->schema([
|
||||
TextInput::make('content')
|
||||
->live(onBlur: true)
|
||||
@@ -113,6 +116,8 @@ Builder\Block::make('heading')
|
||||
|
||||
Any fields that you use from `$state` should be `live()` if you wish to see the item label update live as you use the form.
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x" extras="Key;;string;;$key;;The key for the current block.||State;;array<string, mixed>;;$state;;The raw unvalidated data for the current block.">You can inject various utilities into the function passed to `label()` as parameters.</UtilityInjection>
|
||||
|
||||
<AutoScreenshot name="forms/fields/builder/labelled" alt="Builder with labelled blocks based on the content" version="4.x" />
|
||||
|
||||
### Numbering builder items
|
||||
@@ -129,17 +134,21 @@ Builder::make('content')
|
||||
->blockNumbers(false)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `blockNumbers()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Setting a block's icon
|
||||
|
||||
Blocks may also have an [icon](../../styling/icons), which is displayed next to the label. You can add an icon by passing its name to the `icon()` method:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
|
||||
Builder\Block::make('paragraph')
|
||||
Block::make('paragraph')
|
||||
->icon('heroicon-m-bars-3-bottom-left')
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `icon()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
<AutoScreenshot name="forms/fields/builder/icons" alt="Builder with block icons in the dropdown" version="4.x" />
|
||||
|
||||
### Adding icons to the header of blocks
|
||||
@@ -156,6 +165,79 @@ Builder::make('content')
|
||||
->blockIcons()
|
||||
```
|
||||
|
||||
Optionally, you may pass a boolean value to the `blockIcons()` method to control if the icons are displayed in the block headers:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
// ...
|
||||
])
|
||||
->blockIcons(FeatureFlag::active())
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `blockIcons()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Previewing blocks
|
||||
|
||||
If you prefer to render read-only previews in the builder instead of the blocks' forms, you can use the `blockPreviews()` method. This will render each block's `preview()` instead of the form. Block data will be passed to the preview Blade view in a variable with the same name:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
|
||||
Builder::make('content')
|
||||
->blockPreviews()
|
||||
->blocks([
|
||||
Block::make('heading')
|
||||
->schema([
|
||||
TextInput::make('text')
|
||||
->placeholder('Default heading'),
|
||||
])
|
||||
->preview('filament.content.block-previews.heading'),
|
||||
])
|
||||
```
|
||||
|
||||
In `/resources/views/filament/content/block-previews/heading.blade.php`, you can access the block data like so:
|
||||
|
||||
```blade
|
||||
<h1>
|
||||
{{ $text ?? 'Default heading' }}
|
||||
</h1>
|
||||
```
|
||||
|
||||
Optionally, the `blockPreviews()` method accepts a boolean value to control if the builder should render block previews or not:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
// ...
|
||||
])
|
||||
->blockPreviews(FeatureFlag::active())
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing static values, the `blockPreviews()` and `preview()` methods also accept functions to dynamically calculate them. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Interactive block previews
|
||||
|
||||
By default, preview content is not interactive, and clicking it will open the Edit modal for that block to manage its settings. If you have links and buttons that you'd like to remain interactive in the block previews, you can use the `areInteractive: true` argument of the `blockPreviews()` method:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blockPreviews(areInteractive: true)
|
||||
->blocks([
|
||||
//
|
||||
])
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `areInteractive` argument also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Adding items
|
||||
|
||||
An action button is displayed below the builder to allow the user to add a new item.
|
||||
@@ -174,6 +256,8 @@ Builder::make('content')
|
||||
->addActionLabel('Add a new block')
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `addActionLabel()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Aligning the add action button
|
||||
|
||||
By default, the add action is aligned in the center. You may adjust this using the `addActionAlignment()` method, passing an `Alignment` option of `Alignment::Start` or `Alignment::End`:
|
||||
@@ -189,6 +273,8 @@ Builder::make('content')
|
||||
->addActionAlignment(Alignment::Start)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `addActionAlignment()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Preventing the user from adding items
|
||||
|
||||
You may prevent the user from adding items to the builder using the `addable(false)` method:
|
||||
@@ -203,6 +289,8 @@ Builder::make('content')
|
||||
->addable(false)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `addable()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Deleting items
|
||||
|
||||
An action button is displayed on each item to allow the user to delete it.
|
||||
@@ -221,6 +309,8 @@ Builder::make('content')
|
||||
->deletable(false)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `deletable()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Reordering items
|
||||
|
||||
A button is displayed on each item to allow the user to drag and drop to reorder it in the list.
|
||||
@@ -239,6 +329,8 @@ Builder::make('content')
|
||||
->reorderable(false)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `reorderable()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Reordering items with buttons
|
||||
|
||||
You may use the `reorderableWithButtons()` method to enable reordering items with buttons to move the item up and down:
|
||||
@@ -255,6 +347,20 @@ Builder::make('content')
|
||||
|
||||
<AutoScreenshot name="forms/fields/builder/reorderable-with-buttons" alt="Builder that is reorderable with buttons" version="4.x" />
|
||||
|
||||
Optionally, you may pass a boolean value to control if the builder should be ordered with buttons or not:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
// ...
|
||||
])
|
||||
->reorderableWithButtons(FeatureFlag::active())
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `reorderableWithButtons()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Preventing reordering with drag and drop
|
||||
|
||||
You may use the `reorderableWithDragAndDrop(false)` method to prevent items from being ordered with drag and drop:
|
||||
@@ -269,6 +375,8 @@ Builder::make('content')
|
||||
->reorderableWithDragAndDrop(false)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `reorderableWithDragAndDrop()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Collapsing items
|
||||
|
||||
The builder may be `collapsible()` to optionally hide content in long forms:
|
||||
@@ -297,6 +405,21 @@ Builder::make('content')
|
||||
|
||||
<AutoScreenshot name="forms/fields/builder/collapsed" alt="Collapsed builder" version="4.x" />
|
||||
|
||||
Optionally, the `collaptible()` and `collapsed()` methods accept a boolean value to control if the builder should be collapsible and collapsed or not:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
// ...
|
||||
])
|
||||
->collapsible(FeatureFlag::active())
|
||||
->collapsed(FeatureFlag::active())
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing static values, the `collapsible()` and `collapsed()` methods also accept functions to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Cloning items
|
||||
|
||||
You may allow builder items to be duplicated using the `cloneable()` method:
|
||||
@@ -311,7 +434,7 @@ Builder::make('content')
|
||||
->cloneable()
|
||||
```
|
||||
|
||||
<AutoScreenshot name="forms/fields/builder/cloneable" alt="Builder repeater" version="4.x" />
|
||||
<AutoScreenshot name="forms/fields/builder/cloneable" alt="Cloneable repeater" version="4.x" />
|
||||
|
||||
## Customizing the block picker
|
||||
|
||||
@@ -336,6 +459,8 @@ This method can be used in a couple of different ways:
|
||||
|
||||
Breakpoints (`sm`, `md`, `lg`, `xl`, `2xl`) are defined by Tailwind, and can be found in the [Tailwind documentation](https://tailwindcss.com/docs/responsive-design#overview).
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `blockPickerColumns()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Increasing the width of the block picker
|
||||
|
||||
When you [increase the number of columns](#changing-the-number-of-columns-in-the-block-picker), the width of the dropdown should increase incrementally to handle the additional columns. If you'd like more control, you can manually set a maximum width for the dropdown using the `blockPickerWidth()` method. Options correspond to [Tailwind's max-width scale](https://tailwindcss.com/docs/max-width). The options are `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`, `6xl`, `7xl`:
|
||||
@@ -351,42 +476,27 @@ Builder::make()
|
||||
])
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `blockPickerWidth()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Limiting the number of times a block can be used
|
||||
|
||||
By default, each block can be used in the builder an unlimited number of times. You may limit this using the `maxItems()` method on a block:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
|
||||
Builder\Block::make('heading')
|
||||
Block::make('heading')
|
||||
->schema([
|
||||
// ...
|
||||
])
|
||||
->maxItems(1)
|
||||
```
|
||||
|
||||
## Builder validation
|
||||
|
||||
As well as all rules listed on the [validation](../validation) page, there are additional rules that are specific to builders.
|
||||
|
||||
### Number of items validation
|
||||
|
||||
You can validate the minimum and maximum number of items that you can have in a builder by setting the `minItems()` and `maxItems()` methods:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
// ...
|
||||
])
|
||||
->minItems(1)
|
||||
->maxItems(5)
|
||||
```
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing a static value, the `maxItems()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Using `$get()` to access parent field values
|
||||
|
||||
All form components are able to [use `$get()` and `$set()`](../advanced) to access another field's value. However, you might experience unexpected behavior when using this inside the builder's schema.
|
||||
All form components are able to [use `$get()` and `$set()`](overview#injecting-the-state-of-another-field) to access another field's value. However, you might experience unexpected behavior when using this inside the builder's schema.
|
||||
|
||||
This is because `$get()` and `$set()`, by default, are scoped to the current builder item. This means that you are able to interact with another field inside that builder item easily without knowing which builder item the current form component belongs to.
|
||||
|
||||
@@ -414,6 +524,27 @@ You can use `../` to go up a level in the data structure, so `$get('../client_id
|
||||
|
||||
The special case of `$get()` with no arguments, or `$get('')` or `$get('./')`, will always return the full data array for the current builder item.
|
||||
|
||||
## Builder validation
|
||||
|
||||
As well as all rules listed on the [validation](../validation) page, there are additional rules that are specific to builders.
|
||||
|
||||
### Number of items validation
|
||||
|
||||
You can validate the minimum and maximum number of items that you can have in a builder by setting the `minItems()` and `maxItems()` methods:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
// ...
|
||||
])
|
||||
->minItems(1)
|
||||
->maxItems(5)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x">As well as allowing static values, the `minItems()` and `maxItems()` methods also accept a function to dynamically calculate them. You can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
## Customizing the builder item actions
|
||||
|
||||
This field uses action objects for easy customization of buttons within it. You can customize these buttons by passing a function to an action registration method. The function has access to the `$action` object, which you can use to [customize it](../../actions/trigger-button). The following methods are available to customize the actions:
|
||||
@@ -445,6 +576,8 @@ Builder::make('content')
|
||||
)
|
||||
```
|
||||
|
||||
<UtilityInjection set="formFields" version="4.x" extras="Action;;Filament\Actions\Action;;$action;;The action object to customize.">The action registration methods can inject various utilities into the function as parameters.</UtilityInjection>
|
||||
|
||||
### Confirming builder actions with a modal
|
||||
|
||||
You can confirm actions with a modal by using the `requiresConfirmation()` method on the action object. You may use any [modal customization method](../../actions/modals) to change its content and behavior:
|
||||
@@ -462,21 +595,24 @@ Builder::make('content')
|
||||
)
|
||||
```
|
||||
|
||||
> The `addAction()`, `addBetweenAction()`, `collapseAction()`, `collapseAllAction()`, `expandAction()`, `expandAllAction()` and `reorderAction()` methods do not support confirmation modals, as clicking their buttons does not make the network request that is required to show the modal.
|
||||
<Aside variant="info">
|
||||
The `addAction()`, `addBetweenAction()`, `collapseAction()`, `collapseAllAction()`, `expandAction()`, `expandAllAction()` and `reorderAction()` methods do not support confirmation modals, as clicking their buttons does not make the network request that is required to show the modal.
|
||||
</Aside>
|
||||
|
||||
### Adding extra item actions to a builder
|
||||
|
||||
You may add new [action buttons](../../schemas/actions) to the header of each builder item by passing `Action` objects into `extraItemActions()`:
|
||||
You may add new [action buttons](../primes/actions-in-schemas) to the header of each builder item by passing `Action` objects into `extraItemActions()`:
|
||||
|
||||
```php
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
Builder::make('content')
|
||||
->blocks([
|
||||
Builder\Block::make('contactDetails')
|
||||
Block::make('contactDetails')
|
||||
->schema([
|
||||
TextInput::make('email')
|
||||
->label('Email address')
|
||||
@@ -524,49 +660,6 @@ $state[Str::uuid()] = [
|
||||
$component->state($state);
|
||||
```
|
||||
|
||||
## Previewing blocks
|
||||
|
||||
If you prefer to render read-only previews in the builder instead of the blocks' forms, you can use the `blockPreviews()` method. This will render each block's `preview()` instead of the form. Block data will be passed to the preview Blade view in a variable with the same name:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
use Filament\Forms\Components\Builder\Block;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
|
||||
Builder::make('content')
|
||||
->blockPreviews()
|
||||
->blocks([
|
||||
Block::make('heading')
|
||||
->schema([
|
||||
TextInput::make('text')
|
||||
->placeholder('Default heading'),
|
||||
])
|
||||
->preview('filament.content.block-previews.heading'),
|
||||
])
|
||||
```
|
||||
|
||||
In `/resources/views/filament/content/block-previews/heading.blade.php`, you can access the block data like so:
|
||||
|
||||
```blade
|
||||
<h1>
|
||||
{{ $text ?? 'Default heading' }}
|
||||
</h1>
|
||||
```
|
||||
|
||||
### Interactive block previews
|
||||
|
||||
By default, preview content is not interactive, and clicking it will open the Edit modal for that block to manage its settings. If you have links and buttons that you'd like to remain interactive in the block previews, you can use the `areInteractive: true` argument of the `blockPreviews()` method:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Builder;
|
||||
|
||||
Builder::make('content')
|
||||
->blockPreviews(areInteractive: true)
|
||||
->blocks([
|
||||
//
|
||||
])
|
||||
```
|
||||
|
||||
## Testing builders
|
||||
|
||||
Internally, builders generate UUIDs for items to keep track of them in the Livewire HTML easier. This means that when you are testing a form with a builder, you need to ensure that the UUIDs are consistent between the form and the test. This can be tricky, and if you don't do it correctly, your tests can fail as the tests are expecting a UUID, not a numeric key.
|
||||
|
||||
Reference in New Issue
Block a user