表单
自定义字段
简介
Livewire 组件是在用户浏览器中保存其状态的 PHP 类。当网络请求发起时,其状态发送到服务器,在 Livewire 组件中填入公共属性,这些属性可以如同其他 PHP 类属性一样用同样的方式访问。
假设你的 Livewire 组件有一个公共属性 $name
。你可以以两种方式将该属性绑定到 Livewire 组件的 HTML 输入字段中:使用 wire:model
属性或者通过 Alpine.js 属性 entangling使用它:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<input wire:model="name" />
<!-- Or -->
<div x-data="{ state: $wire.$entangle('name') }">
<input x-model="state" />
</div>
</x-dynamic-component>
当用户输入到输入字段时,$name
属性在 Livewire 组件类上同步更新。当用户提交表单时,$name
属性发送到服务器,并可以将其保存。
这是 Filament 中字段的基本工作原理。每个字段在 Livewire 中分配了一个公共属性,该字段的状态存入其中。我们将该属性名称之为字段的 “state path”。你可以在字段视图中使用 $getStatePath()
函数访问该字段的状态路径(state path):
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<input wire:model="{{ $getStatePath() }}" />
<!-- Or -->
<div x-data="{ state: $wire.$entangle('{{ $getStatePath() }}') }">
<input x-model="state" />
</div>
</x-dynamic-component>
如果你的组件严重依赖第三方库,我们建议你使用 Filament asset 系统异步加载 Alpine.js 组件。这能确保 Alpine.js 组件只会在需要时加载,而不会在每个页面上都加载。要了解如何实现该加载方式,请查看静态资源文档。
自定义字段类
你可以创建自己的自定义字段类和视图,使之在你的整个项目中重复使用,甚至可以将之做成插件发布到社区。
要创建自定义字段类和视图,请使用如下命令:
php artisan make:filament-form-field LocationPicker
这将会生成如下组件类:
use Filament\Forms\Components\Field;
class LocationPicker extends Field
{
protected string $view = 'filament.forms.components.location-picker';
}
它同时会生成一个视图文件:resources/views/filament/forms/components/location-picker.blade.php
。
NOTE
Filament 表单字段不是 Livewire 组件。在 表单字段类中定义公共属性和方法,不会让他们可以在 Blade 视图中可访问。
在 Blade 视图中访问另一个组件的状态
在 Blade 视图中,使用 $get()
函数,你可以访问 Schema 中另一个组件的状态:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
{{ $get('email') }}
</x-dynamic-component>
TIP
Unless a form field is reactive, the Blade view will not refresh when the value of the field changes, only when the next user interaction occurs that makes a request to the server. If you need to react to changes in a field’s value, it should be live()
.
在 Blade 视图中访问 Eloquent 记录
Inside the Blade view, you may access the current Eloquent record using the $record
variable:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
{{ $record->name }}
</x-dynamic-component>
在 Blade 视图中访问当前操作
Inside the Blade view, you may access the current operation, usually create
, edit
or view
, using the $operation
variable:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
@if ($operation === 'create')
This is a new conference.
@else
This is an existing conference.
@endif
</x-dynamic-component>
在 Blade 视图中访问当前 Livewire 组件实例
Inside the Blade view, you may access the current Livewire component instance using $this
:
@php
use Filament\Resources\Users\RelationManagers\ConferencesRelationManager;
@endphp
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
@if ($this instanceof ConferencesRelationManager)
You are editing conferences the of a user.
@endif
</x-dynamic-component>
在 Blade 视图中访问当前字段实例
Inside the Blade view, you may access the current field instance using $field
. You can call public methods on this object to access other information that may not be available in variables:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
@if ($field->getState())
This is a new conference.
@endif
</x-dynamic-component>
添加配置方法到自定义字段类
You may add a public method to the custom field class that accepts a configuration value, stores it in a protected property, and returns it again from another public method:
use Filament\Forms\Components\Field;
class LocationPicker extends Field
{
protected string $view = 'filament.forms.components.location-picker';
protected ?float $zoom = null;
public function zoom(?float $zoom): static
{
$this->zoom = $zoom;
return $this;
}
public function getZoom(): ?float
{
return $this->zoom;
}
}
Now, in the Blade view for the custom field, you may access the zoom using the $getZoom()
function:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
{{ $getZoom() }}
</x-dynamic-component>
Any public method that you define on the custom field class can be accessed in the Blade view as a variable function in this way.
To pass the configuration value to the custom field class, you may use the public method:
use App\Filament\Forms\Components\LocationPicker;
LocationPicker::make('location')
->zoom(0.5)
Allowing utility injection in a custom field configuration method
Utility injection is a powerful feature of Filament that allows users to configure a component using functions that can access various utilities. You can allow utility injection by ensuring that the parameter type and property type of the configuration allows the user to pass a Closure
. In the getter method, you should pass the configuration value to the $this->evaluate()
method, which will inject utilities into the user’s function if they pass one, or return the value if it is static:
use Closure;
use Filament\Forms\Components\Field;
class LocationPicker extends Field
{
protected string $view = 'filament.forms.components.location-picker';
protected float | Closure | null $zoom = null;
public function zoom(float | Closure | null $zoom): static
{
$this->zoom = $zoom;
return $this;
}
public function getZoom(): ?float
{
return $this->evaluate($this->zoom);
}
}
Now, you can pass a static value or a function to the zoom()
method, and inject any utility as a parameter:
use App\Filament\Forms\Components\LocationPicker;
LocationPicker::make('location')
->zoom(fn (Conference $record): float => $record->isGlobal() ? 1 : 0.5)
Obeying state binding modifiers
When you bind a field to a state path, you may use the defer
modifier to ensure that the state is only sent to the server when the user submits the form, or whenever the next Livewire request is made. This is the default behavior.
However, you may use the live()
on a field to ensure that the state is sent to the server immediately when the user interacts with the field. This allows for lots of advanced use cases as explained in the reactivity section of the documentation.
Filament provides a $applyStateBindingModifiers()
function that you may use in your view to apply any state binding modifiers to a wire:model
or $wire.$entangle()
binding:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<input {{ $applyStateBindingModifiers('wire:model') }}="{{ $getStatePath() }}" />
<!-- Or -->
<div x-data="{ state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$getStatePath()}')") }} }">
<input x-model="state" />
</div>
</x-dynamic-component>
Edit on GitHubStill need help? Join our Discord community or open a GitHub discussion