Languages

Version

Theme

表单

自定义字段

简介

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 记录

在 Blade 视图中,使用 $record 变量,你可以访问当前 Eloquent 记录:

<x-dynamic-component
    :component="$getFieldWrapperView()"
    :field="$field"
>
    {{ $record->name }}
</x-dynamic-component>

在 Blade 视图中访问当前操作

在 Blade 视图中,使用 $operation 变量,你可以访问当前操作(通常是 createedit 或者 view):

<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 组件实例

在 Blade 视图中,你可以使用 $this 访问当前 Livewire 组件:

@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 视图中访问当前字段实例

在 Blade 视图中,你可以使用 $field 访问当前字段实例。你可以在这个对象上调用公共方法,访问其他以变量形式访问不到的信息:

<x-dynamic-component
    :component="$getFieldWrapperView()"
    :field="$field"
>
    @if ($field->getState())
        This is a new conference.
    @endif
</x-dynamic-component>

添加配置方法到自定义字段类

你可以向自定义字段类添加一个接受配置值的公共方法,将其存储在受保护的属性中,并在另一个公共方法返回:

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;
    }
}

现在,在该自定义字段的 Blade 视图中,你可以使用 $getZoom() 函数访问这个 zoom:

<x-dynamic-component
    :component="$getFieldWrapperView()"
    :field="$field"
>
    {{ $getZoom() }}
</x-dynamic-component>

你在自定义字段类中定义的所有公共方法,都可以通过这种方法在 Blade 视图作为变量函数中访问。

要传递配置值到自定义字段类,你可以使用公共方法:

use App\Filament\Forms\Components\LocationPicker;

LocationPicker::make('location')
    ->zoom(0.5)

允许将 utility 注入到自定义字段配置方法中

Utility 注入是一个强大的 Filament 特性,允许用户使用接受 utility 的函数配置组件。你可以通过确保参数类型和配置属性名允许传入闭包来允许 utility 注入。在 getter 方法中,你应该将配置值传入到 $this->evaluate() 方法,使之将 utility 注入到用户函数(如果用户传入了),或者返回其值(如果是静态值):

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);
    }
}

现在,你可以传入静态值或者函数到 zoom() 方法中,同时注入任何 utility 作为参数:

use App\Filament\Forms\Components\LocationPicker;

LocationPicker::make('location')
    ->zoom(fn (Conference $record): float => $record->isGlobal() ? 1 : 0.5)

遵守状态绑定修饰符

当你将字段绑定到一个 state path 时,你可能会使用 defer 修饰符以确保该状态只在用户提交表单时或者下次发起 Livewire 请求时发送到服务器。这是默认行为

不过,你也可以在字段上使用 live() 以确保在用户与该字段交互时立即将该状态发送到服务器。这可以允许许多高级用法,请参考文档中的响应式相关内容

Filament 提供了一个 $applyStateBindingModifiers() 函数,你可以在视图中使用,以将状态绑定修饰符应用到 wire:model 或者 $wire.$entangle() 绑定:

<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 GitHub

Still need help? Join our Discord community or open a GitHub discussion

Previous
Hidden