FilamentF
Filament15mo ago
ericmp

How to Check Unique Field Names Across Sections in Nested Repeater?

The user is filling a form which creates this structure (an array of sections containing fields):
[
    {
        "name": "Section 1",
        "fields": [
            {
                "name": "Field 1"
            },
            {
                "name": "Field 2"
            }
        ]
    },
    {
        "name": "Section 1",
        "fields": [
            {
                "name": "Field 1"
            },
            {
                "name": "Field 2"
            }
        ]
    }
]

The problem is that i want the names to be unique. For the sections, is easy:
Forms\Components\Repeater::make('sections')
    ->schema([
        Forms\Components\TextInput::make('name')
            ->distinct()

But then, for the fields:

I don't know how to specify that I want them to be unique for the current section but also in other sections
Forms\Components\Repeater::make('sections')
    ->schema([
        Forms\Components\TextInput::make('name')
            ->distinct()
            ->schema([
                Forms\Components\Repeater::make('fields')
                    Forms\Components\TextInput::make('name')
                        ->distinct() // how to specify that must be distinct in all sections, not only current one?

What would u do?
Solution
solved:
use Livewire\Component as Livewire;

...

Forms\Components\Repeater::make('sections')
    ->schema([
        Forms\Components\TextInput::make('name')
            ->distinct()
            ->schema([
                Forms\Components\Repeater::make('fields')
                    Forms\Components\TextInput::make('name')
                        ->rule(function (Get $get, Livewire $livewire): \Closure {
                            return function (string $attribute, $value, \Closure $fail) use ($livewire): void {
                                $fieldsNames = collect($livewire->data['sections'])->pluck('fields.*.name')->flatten(depth: 1);

                                $nameIsRepeated = (function () use ($fieldsNames, $value): bool {
                                    return $fieldsNames->filter(function (string $fieldName) use ($value): bool {
                                        return $fieldName === $value;
                                    })->count() > 1;
                                })();

                                if ($nameIsRepeated) {
                                    $fail(__('validation.distinct'));
                                }
                            };
                        })


if anyone has any improvements, let me know please. ping me
Was this page helpful?