Languages

Version

Theme

组件

Rendering an action in a Livewire component

设置 Livewire 组件

首先,生成新的 Livewire 组件:

php artisan make:livewire ManageProduct

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

@livewire('manage-product')

Alternat或者,你可以使用全页 Livewire 组件:

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

Route::get('products/{product}/manage', ManageProduct::class);

你必须使用 InteractsWithActionsInteractsWithForms traits,并在你的 Livewire 组件类中实现 HasActionsHasForms 接口:

use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;

class ManagePost extends Component implements HasForms, HasActions
{
    use InteractsWithActions;
    use InteractsWithForms;

    // ...
}

添加 Action

添加一个返回 Action 的方法。该方法必须与 Action 的名称相同,或者在名称后面标明 Action

use App\Models\Post;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;

class ManagePost extends Component implements HasForms, HasActions
{
    use InteractsWithActions;
    use InteractsWithForms;

    public Post $post;

    public function deleteAction(): Action
    {
        return Action::make('delete')
            ->requiresConfirmation()
            ->action(fn () => $this->post->delete());
    }
    
    // This method name also works, since the action name is `delete`:
    // public function delete(): Action
    
    // This method name does not work, since the action name is `delete`, not `deletePost`:
    // public function deletePost(): Action

    // ...
}

最后,你需要在视图中渲染该 Action。为此,你需要 {{ $this->deleteAction }},将 deleteAction 替换成你的 Action 方法名:

<div>
    {{ $this->deleteAction }}

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

你也需要 <x-filament-actions::modals />,在其中注入所需的 HTML 来渲染 Action 模态框。这只需要在 Livewire 组件内引入一次,不论你对该组件有多少次操作。

传递 Action 参数

有时,你可能希望传递参数到你的 Action 中。比如,如果你在同一个视图中渲染同一个 Action 多次,不过每次使用不同模型,你可以传入模型 ID 作为参数,然后稍后对其进行检索。为此,你可以在视图中调用该 Action,并传入以数组方式传入参数:

<div>
    @foreach ($posts as $post)
        <h2>{{ $post->title }}</h2>

        {{ ($this->deleteAction)(['post' => $post->id]) }}
    @endforeach

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

现在,你可以在 action 方法中访问该 post ID:

use App\Models\Post;
use Filament\Actions\Action;

public function deleteAction(): Action
{
    return Action::make('delete')
        ->requiresConfirmation()
        ->action(function (array $arguments) {
            $post = Post::find($arguments['post']);

            $post?->delete();
        });
}

在 Livewire 视图中隐藏 Action

如果使用 hidden()visible() 控制 Action 是否渲染,应该此 Action 包装在 @if 中检测其是否可见(isVisible()):

<div>
    @if ($this->deleteAction->isVisible())
        {{ $this->deleteAction }}
    @endif
    
    {{-- Or --}}
    
    @if (($this->deleteAction)(['post' => $post->id])->isVisible())
        {{ ($this->deleteAction)(['post' => $post->id]) }}
    @endif
</div>

hidden()visable() 方法也控制着 Action 是否禁用 disabled(),因此如果用户没有权限,它们仍然可以用来保护 Action 不被运行。将此逻辑封装在 Action 自己的 hidden()visible() 中是一种很好的实践,否则你需要在视图和 disabled() 中定义条件。

您还可以利用此功能来隐藏 Action 隐藏时可能不需要渲染的任何包装元素:

<div>
    @if ($this->deleteAction->isVisible())
        <div>
            {{ $this->deleteAction }}
        </div>
    @endif
</div>

在 Livewire 视图中对 Action 进行分组

通过使用 <x-filament-actions::group> Blade 组件,传递 actions 数组作为属性,你可以将 Action 分组到一个下拉菜单

<div>
    <x-filament-actions::group :actions="[
        $this->editAction,
        $this->viewAction,
        $this->deleteAction,
    ]" />

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

你也可以传入任何属性去自定义触发按钮及下拉菜单的外观:

<div>
    <x-filament-actions::group
        :actions="[
            $this->editAction,
            $this->viewAction,
            $this->deleteAction,
        ]"
        label="Actions"
        icon="heroicon-m-ellipsis-vertical"
        color="primary"
        size="md"
        tooltip="More actions"
        dropdown-placement="bottom-start"
    />

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

链式调用 Action

通过调用 replaceMountedAction() 方法,你可以链式调用多个 Action,这样你就可以可以在当前 Action 执行完毕后,将其替换成其他 Action:

use App\Models\Post;
use Filament\Actions\Action;

public function editAction(): Action
{
    return Action::make('edit')
        ->form([
            // ...
        ])
        // ...
        ->action(function (array $arguments) {
            $post = Post::find($arguments['post']);

            // ...

            $this->replaceMountedAction('publish', $arguments);
        });
}

public function publishAction(): Action
{
    return Action::make('publish')
        ->requiresConfirmation()
        // ...
        ->action(function (array $arguments) {
            $post = Post::find($arguments['post']);

            $post->publish();
        });
}

现在,当第一个 Action 提交后,第二个 Action 会在原先第一个 Action 所处的位置打开。原本传递到第一个 Action 的参数将会传递到第二个 Action,这样你就可以使用它们在请求间持久化数据。

如果第一个 Action 取消了,第二个就不会打开。如果第二个取消,第一个已经运行过,就不能再取消。

编码触发 Action

有时,你可能需要在用户不点击内置触发按钮的情况下触发操作(Action),尤其是从 JavaScript 中触发。以下是可以在 Livewire 组件上注册的 Action 示例:

use Filament\Actions\Action;

public function testAction(): Action
{
    return Action::make('test')
        ->requiresConfirmation()
        ->action(function (array $arguments) {
            dd('Test action called', $arguments);
        });
}

你可以使用 wire:click 属性,调用 mountAction() 方法,并可选地传入你希望可用的任何参数,在 HTML 中单击触发该操作(Action):

<button wire:click="mountAction('test', { id: 12345 })">
    Button
</button>

要在 JavaScript 中触发该 Action,你可以使用 $wire utility,并传入相同的参数:

$wire.mountAction('test', { id: 12345 })
Edit on GitHub

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

Previous
概述