组件

Rendering a form in a Blade view

NOTE

继续之前,请确保项目中已经安装了 filament/forms。你可以运行如下命令检查是否已安装:

composer show filament/forms

如果还未安装,请转到安装指南,并根据指示配置单个组件

设置 Livewire 组件

首先,生成新的 Livewire 组件:

php artisan make:livewire CreatePost

然后,在页面中渲染该 Livewire 组件:

@livewire('create-post')

此外,你可以使用全页 Livewire 组件:

use App\Livewire\CreatePost;
use Illuminate\Support\Facades\Route;

Route::get('posts/create', CreatePost::class);

添加表单

NOTE

继续之前,请确保项目中已经安装了表单构造器包。详情请查阅安装指南,并根据指示配置单个组件

添加表单到 Livewire 组件类有 5 个重要步骤:

  1. 实现 HasForms 接口并使用 InteractsWithForms trait。
  2. 定义公共 Livewire 属性,来保存表单数据。在我们的例子中,我们把这个属性叫做 $data,不过你可以根据需要进行命名。
  3. 添加 form() 方法,这是你配置表单的地方。然后添加表单 Schema,并告诉 Filament 在 $data 属性中保存表单数据(使用 statePath('data'))。
  4. mount() 中调用 $this->form->fill(),初始化表单。这对于每个表单都是必不可少的,即使它没有初始化任何数据。
  5. 定义一个方法来处理表单提交。在我们的示例中,我们使用 create(),你也可以自己命名。在该方法内,你可以使用 $this->form->getState() 验证和获取表单数据。使用该方法,而不是直接获取 $this->data 属性,因为表单数据需要在返回前验证并转换成有效格式。
<?php

namespace App\Livewire;

use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Concerns\RestrictsFileUploadsToSchemaComponents;
use Filament\Schemas\Contracts\HasSchemas;
use Illuminate\Contracts\View\View;
use Filament\Schemas\Schema;
use Livewire\Component;

class CreatePost extends Component implements HasSchemas
{
    use InteractsWithSchemas;
    use RestrictsFileUploadsToSchemaComponents;

    public ?array $data = [];
    
    public function mount(): void
    {
        $this->form->fill();
    }
    
    public function form(Schema $schema): Schema
    {
        return $schema
            ->components([
                TextInput::make('title')
                    ->required(),
                MarkdownEditor::make('content'),
                // ...
            ])
            ->statePath('data');
    }
    
    public function create(): void
    {
        dd($this->form->getState());
    }
    
    public function render(): View
    {
        return view('livewire.create-post');
    }
}

最后,在 Livewire 组件视图中,渲染表单:

<div>
    <form wire:submit="create">
        {{ $this->form }}
        
        <button type="submit">
            Submit
        </button>
    </form>
    
    <x-filament-actions::modals />
</div>

NOTE

<x-filament-actions::modals /> 用于渲染表单组件 Action 模态框。这段代码可以放在 <form> 元素之外的任何地方,只要它还在 Livewire 组件内。

现在到浏览器访问该 Livewire 组件,你应该就能看到 components() 中的表单组件了。

将表单数据提交,你将会看到表单数据打印到屏幕中。你可以将这些数据存入模型,而不是打印:

use App\Models\Post;

public function create(): void
{
    Post::create($this->form->getState());
}

NOTE

filament/forms 也包含以下这些包:

  • filament/actions
  • filament/schemas
  • filament/support

这些包允许你在 Livewire 组件中使用它们的组件。

比如,如果你的表单中使用了 Action,请记住实现 HasActions 接口并在 Livewire 组件类中使用 InteractsWithActions trait。

如果你在表单中使用其他 Filament 组件,请确保同时安装并集成对应的包。

使用数据初始化表单

要使用数据填充表单,只需将数据传递给 $this->form->fill() 方法。比如,如果你在编辑已有的文章(post),你可以这样做:

use App\Models\Post;

public function mount(Post $post): void
{
    $this->form->fill($post->attributesToArray());
}

使用 $this->form->fill() 方法,而不是直接将数据赋值给 $this->data 属性。这是因为在存入数据库之前,文章的数据需要在内部转换成有用的格式。

NOTE

The data you pass to fill() is exposed to JavaScript as part of the Livewire request. If your model has a column containing binary data that is not valid UTF-8, such as a geometry, point, or blob column, it cannot be serialized to JSON and the page will fail to load, often with a blank screen and no error in the Laravel log.

To resolve this, add the column to the $hidden array on your model, which excludes it from attributesToArray():

protected $hidden = ['location'];

设置表单模型

$form 访问模型有几个原因:

  • 它允许表单中的字段从模型中加载信息。比如,Select 字段可以自动从数据库加载选项
  • 表单可以自动加载并保存模型的关联数据。比如,你有一个编辑文章(Post)的表单,使用 Repeater 管理与文章管理的评论。当调用 $this->form->fill([...]) 时,Filament 会自动为那个 Post 加载评论,并且在调用 $this->form->getState()时,将其保存回关联之中。
  • exists()unique() 这样的验证规则,可以自动从模型中检索数据库表名。

如果存在模型,建议将其传递给表单。如前所述,它可以解锁 Filament 表单构造器的许多新能力。

使用 $form->model() 方法,可以将模型传递给表单:

use Filament\Schemas\Schema;

public Post $post;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            // ...
        ])
        ->statePath('data')
        ->model($this->post);
}

表单提交后传递表单模型

有些情况下,表单模型在表单提交之前是不可用的。比如,创建 Post 的表单中,表单提交之前 post 模型并不存在。因此,你不能将其传入到 $form->model()。不过,你可以传递模型类替代:

use App\Models\Post;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            // ...
        ])
        ->statePath('data')
        ->model(Post::class);
}

就其本身而言,这并不比传递模型实例更强大。比如,关联不会在创建之后保存到 post 中。为此,你需要在 post 创建之后,将其传递给表单,并调用 saveRelationships() 以保存关联:

use App\Models\Post;

public function create(): void
{
    $post = Post::create($this->form->getState());
    
    // Save the relationships from the form to the post after it is created.
    $this->form->model($post)->saveRelationships();
}

将表单数据保存到单独的属性中

在此前所有的示例中,我们将表单数据保存到 Livewire 组件的公共的 $data 属性中。不过,我们也可以将数据保存到单独的属性中。比如,如果表单中有一个 title 字段,你可以将其保存到 title 属性中。为此,根本无需将 statePath() 传递给表单。请确保所有字段在类中都有他们自己的 public 属性。

use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;

public ?string $title = null;

public ?string $content = null;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            TextInput::make('title')
                ->required(),
            MarkdownEditor::make('content'),
            // ...
        ]);
}

使用多个表单

多个表单可以使用 InteractsWithSchemas trait 定义。每个表单应该使用同名方法:

use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;

public ?array $postData = [];

public ?array $commentData = [];

public function editPostForm(Schema $schema): Schema
{
    return $schema
        ->components([
            TextInput::make('title')
                ->required(),
            MarkdownEditor::make('content'),
            // ...
        ])
        ->statePath('postData')
        ->model($this->post);
}

public function createCommentForm(Schema $schema): Schema
{
    return $schema
        ->components([
            TextInput::make('name')
                ->required(),
            TextInput::make('email')
                ->email()
                ->required(),
            MarkdownEditor::make('content')
                ->required(),
            // ...
        ])
        ->statePath('commentData')
        ->model(Comment::class);
}

现在,每个表单都能通过表单名而非 form 定位。比如,你可以使用 $this->editPostForm->fill([...]) 填充文章(Post)表单;或者可以使用 $this->createCommentForm->getState() 获取评论(Comment)表单的数据。

你可以注意到,每个表单都有其唯一的 statePath()。每个表单都会在 Livewire 组件上将其状态(state)写入到不同数组中,因此,定义公开属性(如本例中的 $postData$commentData)很重要:

重置表单数据

通过调用 $this->form->fill(),你可以在任何时候将表单重置回其默认数据。比如,你希望每次提交后,清空表单内容:

use App\Models\Comment;

public function createComment(): void
{
    Comment::create($this->form->getState());

    // Reinitialize the form to clear its data.
    $this->form->fill();
}

使用 CLI 生成表单 Livewire 组件

建议你了解如何使用表单构造器手动创建 Livewire 组件,不过一旦熟悉之后,你可以使用 CLI 命令行来生成表单。

php artisan make:filament-livewire-form RegistrationForm

这将会生成新的 app/Livewire/RegistrationForm.php 组件,你可以对其进行自定义。

为 Eloquent 模型生成表单

Filament 也可以为指定的 Eloquent 模型生成表单。这更为强大,因为它能自动为你保存表单数据,并确保表单字段进行合理配置来访问该模型。

当使用 make:livewire-form 命令生成表单时,它会询问模型名称:

php artisan make:filament-livewire-form Products/CreateProduct

为 Eloquent 记录生成编辑表单

默认情况下,传入模型到 make:livewire-form 会产生一个表单,用于在数据库中生成新记录。如果你传入 --edit 标志到该命令,它会为特定记录生成编辑表单。这回使用记录数据自动填充表单,并在提交后将数据保存回模型中。

php artisan make:filament-livewire-form Products/EditProduct --edit

自动生成表单 Schema

Filament 可以基于模型数据库字段,猜测你想要在 Schema 中添加哪些表单字段。生成表单时,你可以使用 --generate 标志:

php artisan make:filament-livewire-form Products/CreateProduct --generate

Security considerations for file uploads

The InteractsWithSchemas trait exposes Livewire’s file upload RPC methods on every component that uses it — whether or not the form contains an upload field. If your Livewire component is reachable to users you do not want uploading arbitrary files, add the RestrictsFileUploadsToSchemaComponents trait. See Restricting Livewire file uploads to schema components for details.

Edit on GitHub

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

Previous
在 Livewire 组件中渲染 Action