F
Filamentβ€’16mo ago
flex

How to handle records of different "type" and different fields depending on the type?

Hey! I have a simple model called "Visual". It has the fields name (string), type (enum) and settings (json). In a CMS the record should represent any type of visual objects like an image, a slider, a video, a chart, a pdf, whatever.. Each type has completely different fields which should be stored into settings column. So for example image just have a FileUpload. A slider has multiple FileUploads, a chart may have just a Codefield to insert a iframe-code or whatever... How can I use different fields depending on the selected type in the Select for "type"? To may make it little bit more challenging (for me): For each of those visual types we have packages to only install only the types we need for the website. The packages register them self in a VisualTypeRegistry. A VisualType object has a getKey() ``getLabel() and getSchema() function. Building the type Select works well depending on the key and the label. But now I don't know how to tell filament to use the getSchema() for the selected type.
12 Replies
Dan Harrin
Dan Harrinβ€’16mo ago
I would use a Builder field for this it uses 1 json object instead of multiple visual models
flex
flexβ€’16mo ago
But at the end if have may 20 images, 5 sliders and 7 youtube videos. So I would need 32 visual records or do you mean adding a builder field with maxItems(1) and minItems(1) and each visual type will represent one block?
Dan Harrin
Dan Harrinβ€’16mo ago
a block is Image, Slider, YoutubeVideo your JSON contains an array of x items of these types
flex
flexβ€’16mo ago
1 record need to represent 1 visual so I could solve this problem with a builder with using min/max Items 1 but feels like a workaround
Dan Harrin
Dan Harrinβ€’16mo ago
does it need to though? im just talking about the UI here really, the builder was made for this
flex
flexβ€’16mo ago
The problem is, that I want to re-use for example one visual on may 5 different pages. They should be re-usable. I love the builder. The whole CMS and the building of the pages itself depend on the builder.
Dan Harrin
Dan Harrinβ€’16mo ago
so you were planning on using a repeater or something to handle the different reusable blocks? i understand what you mean by maxItems now you could use a Select and then a Grid/Group/Fieldset or something to dynamically generate field based on that
Group::make()->schema(function ($get) {
$select = $get('select name');

return array of fields based on the select.
})->statePath('settings')
Group::make()->schema(function ($get) {
$select = $get('select name');

return array of fields based on the select.
})->statePath('settings')
on the Select, you need ->reactive()->afterStateUpdated(fn ($component) => $component->getContainer()->getComponents()[1]->getChildComponentContainer()->fill()) to ensure that the group is reinitialised when it changes (assuming the Group is the second field in the array, you might need to change 1 to a different index)
flex
flexβ€’16mo ago
@Dan Harrin I think thats definitely the direction I need to go. Unfortunately Group complains about the Closure in the make(). I'm doing something wrong here? return $form ->schema( [ Forms\Components\TextInput::make('name') ->label('Name') ->required(), Forms\Components\Select::make('type') ->options($visualTypeRegistry->getOptions() ) ->reactive() ->afterStateUpdated( fn ($component) => $component->getContainer()->getComponents()[2]->getChildComponentContainer()->fill() ), Forms\Components\Grid::make(function ($get) { $select = $get('type'); return [ Forms\Components\TextInput::make('a field for '.$select) ]; })->statePath('settings'), ] );
flex
flexβ€’16mo ago
Dan Harrin
Dan Harrinβ€’16mo ago
Try Group::make()->schema([
flex
flexβ€’16mo ago
awesome meci πŸ™‚ For editing I wouldn't show the option to change the type at all. But for creation it would be pretty nice to put those fields into a two steps wizard. First for name and type. Second for the settings. Is it possible to adjust this code that it triggers the first components on the second wizard page? $component->getContainer()->getComponents()[2]->getChildComponentContainer()->fill()