跳到主要内容
版本:3.0

在 Livewire 组件中添加表单

设置 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);

添加表单

添加表单到 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 App\Models\Post;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Illuminate\Contracts\View\View;
use Livewire\Component;

class CreatePost extends Component implements HasForms
{
use InteractsWithForms;

public ?array $data = [];

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

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

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

public function render(): View
{
return view('create-post');
}
}

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

<div>
<form wire:submit="create">
{{ $this->form }}

<button type="submit">
Submit
</button>
</form>

<x-filament-actions::modals />
</div>

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

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

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

use App\Models\Post;

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

使用数据初始化表单

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

use App\Models\Post;

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

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

设置表单模型

$form 访问模型有几个用处:

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

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

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

use App\Models\Post;
use Filament\Forms\Form;

public Post $post;

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

表单提交后传递表单模型

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

use App\Models\Post;
use Filament\Forms\Form;

public function form(Form $form): Form
{
return $form
->schema([
// ...
])
->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\TextInput;
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Form;

public ?string $title = null;

public ?string $content = null;

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

使用多种表单Using multiple forms

默认情况下,InteractsWithForms trait 每个 Livewire 组件只能处理一个表单 —— 即 form()。要添加多个表单到 Livewire 组件,你可以在 getForms() 方法中定义,并返回包含每个表单名的数组:

protected function getForms(): array
{
return [
'editPostForm',
'createCommentForm',
];
}

现在,通过与上述表单名同名的方法,每个表单都能在 Livewire 组件中定义:

use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Form;

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

public function createCommentForm(Form $form): Form
{
return $form
->schema([
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)写入到不同数组中,因此,定义如下数组很重要:

public ?array $postData = [];
public ?array $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:livewire-form RegistrationForm

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

为 Eloquent 模型生成表单

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

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

php artisan make:livewire-form Products/CreateProduct

为 Eloquent 记录生成编辑表单

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

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

自动生成表单 Schema

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

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

如果标中包含 ENUM 字段,doctrine/dbal 将会无法扫描表并且崩溃。因此,如果包含 ENUM 字段,Filament 将无法生成 Schema。更多关于该问题的信息,请查阅此处