Tricks

在下拉列表选项中渲染HTML

Jul 23, 2022
Martin
Admin panel, Form builder

有时候,单一的属性信息不足以在下拉列表选项中获取正确的记录。当然,你可以使用访问器(accessor)联结属性,不过这样可能不是很美观。假如我们需要展示图片呢?或许我们需要一点HTML。

由于 Filament 使用了 Choice.js, 我们可以在每个下拉选项中渲染HTML。你只需在定义下拉列表字段时,使用 allowHtml() 方法就可以开启这一功能。

以下是带有头像的用户下拉列表的通用示例:

Select::make('user_id')
->label('User')
->allowHtml() // Apply the new modifier to enable HTML in the options - it's disabled by default
->searchable() // Don't forget to make it searchable otherwise there is no choices.js magic!
->getSearchResultsUsing(function (string $search) {
$users = User::where('name', 'like', "%{$search}%")->limit(50)->get();
 
return $users->mapWithKeys(function ($user) {
return [$user->getKey() => static::getCleanOptionString($user)];
})->toArray();
})
->getOptionLabelUsing(function ($value): string {
$user = User::find($value);
 
return static::getCleanOptionString($user);
})

->getSearchResultsUsing() - 返回搜索结果的键值对。键(key)为模型(用户)ID, 值为HTML字符串。

->getOptionLabelUsing() - 返回 HTML 字符串。

To keep it DRY I've added a static method to the resource to return the view.

public static function getCleanOptionString(Model $model): string
{
return Purify::clean(
view('filament.components.select-user-result')
->with('name', $model?->name)
->with('email', $model?->email)
->with('image', $model?->image)
->render()
);
}

注意:启用 allowHtml() 可能会有XSS攻击风险。请净化HTML字符串以保证安全!

最后,为视图创建 blade 模板文件

<div class="flex rounded-md relative">
<div class="flex">
<div class="px-2 py-3">
<div class="h-10 w-10">
<img src="{{ url('/storage/'.$image.'') }}" alt="{{ $name }}" role="img" class="h-full w-full rounded-full overflow-hidden shadow object-cover" />
</div>
</div>
 
<div class="flex flex-col justify-center pl-3 py-2">
<p class="text-sm font-bold pb-1">{{ $name }}</p>
<div class="flex flex-col items-start">
<p class="text-xs leading-5">{{ $email }}</p>
</div>
</div>
</div>
</div>