Many-To-Many relation and edit form

Hello. I've a question: I have the following model for which I want to create a way to insert records. So basically I want to have some form that let's me first select a VacancyType, then based on that value I want to select one or more VacancyTypeClassifications. And then this selection should be saved within the VacancyClassification table. I was able to create this depended select boxes, but I'm stuck within my VacancyResource on how to add the right values into the many-to-many table. This table doesn't have pivot values, only ID's and times. Hope this is clear and that anyone has a tip for me?
22 Replies
Daniel Plomp
Daniel Plomp16mo ago
Anyone? squint
Dan Harrin
Dan Harrin16mo ago
normal relationship select for the type multiple relationship select for the classifications, which saves to the many-many relationship you can scope the many-many options using the third parameter of relationship() and $get()ting the first select value
Daniel Plomp
Daniel Plomp16mo ago
Hi Dan. Thanks for the reply. I'm not sure if I follow, sorry! Should I start from a RelationManager, or can I also work with e.g. a Select and Select Multiple directly on my VacancyResource? I have configured it like this:
Forms\Components\Select::make('vacancy_type')
->options(VacancyType::all()->pluck('name', 'id')->toArray())
->reactive()
->afterStateUpdated(fn(callable $set) => $set('vacancy_classifications', null)),

Forms\Components\Select::make('vacancy_classifications')
->options(function (callable $get) {

$vacancyType = VacancyType::find($get('vacancy_type'));
if (!$vacancyType)
return null;

return $vacancyType->vacancy_type_classifications()->pluck('name', 'id')->toArray();
})
->multiple()
Forms\Components\Select::make('vacancy_type')
->options(VacancyType::all()->pluck('name', 'id')->toArray())
->reactive()
->afterStateUpdated(fn(callable $set) => $set('vacancy_classifications', null)),

Forms\Components\Select::make('vacancy_classifications')
->options(function (callable $get) {

$vacancyType = VacancyType::find($get('vacancy_type'));
if (!$vacancyType)
return null;

return $vacancyType->vacancy_type_classifications()->pluck('name', 'id')->toArray();
})
->multiple()
Daniel Plomp
Daniel Plomp16mo ago
Daniel Plomp
Daniel Plomp16mo ago
Which work But it doesn't get saved to the many-to-many table I guess it would make more sense to use a RelationManager that shows the VacancyClassification records. When creating a new one, I would like to see maybe a popup with these select fields. How would you do that? Sorry, pretty new to Filament...
Dan Harrin
Dan Harrin16mo ago
to start with, on the first select use ->options(fn () => VacancyType::all()->pluck('name', 'id')->toArray()) which will result in better performance ->afterStateUpdated(fn(callable $set) => $set('vacancy_classifications', null)), should be ->afterStateUpdated(fn(callable $set) => $set('vacancy_classifications', [])), as the classifications are stored in an array on the second select, replace options() with relationship('vacancy_classifications', 'name', fn ($query, $get) => $query->where('type_id', $get('vacancy_type'))) the selected options of the second select will save to the pivot table automatically.
Daniel Plomp
Daniel Plomp16mo ago
OK, I'll try that first. But that would be the approach without a RelationManager right? Just the two Select Components on my VacancyResource?
Dan Harrin
Dan Harrin16mo ago
yup relationmanager is an overkill if you only have a Name field IMO
Daniel Plomp
Daniel Plomp16mo ago
I see. I'll check this. Thanks for the help so far. OK, that works. Well, I can select a Vacancy Type and then the Vacancy Classifications. They are added to the Vacancy_Classifications table. If I re-open the Vacancy and add some other options, the existing ones are deleted and the new ones are added. 🙂 How does that work?
Daniel Plomp
Daniel Plomp16mo ago
To make it more complex: this is the screen I would like to rebuild. An overview of the Vacancy Types with their Classifications. One can select one or more options in every list.
Daniel Plomp
Daniel Plomp16mo ago
I know... this is a very old ASP / VB.NET application.
Dan Harrin
Dan Harrin16mo ago
not sure about that one not the same UI but the easiest way would be to remove the type select and the third relationship() parameter and just select classifications across groups but TBH, i think your database structure is probably to blame each classification type should be in a separate table and use separate relationships
Daniel Plomp
Daniel Plomp16mo ago
Hmm... you think? I find it a valid model? Maybe I'll look into using a RelationManager anyways...
Dan Harrin
Dan Harrin16mo ago
i dont think the relation manager will help much
Daniel Plomp
Daniel Plomp15mo ago
Still struggling with this one. I got some second opinions on my database model, but it seems correct. If I setup the RelationManager to just show the many-to-many table, it looks like this. I just refer to the field names in the joint tables:
Tables\Columns\TextColumn::make('vacancy_type_classification.vacancy_type.name')
->label(__('strings.models.vacancy_types.single')),
Tables\Columns\TextColumn::make('vacancy_type_classification.name')
->label(__('strings.models.vacancy_type_classification.single')),
Tables\Columns\TextColumn::make('vacancy_type_classification.vacancy_type.name')
->label(__('strings.models.vacancy_types.single')),
Tables\Columns\TextColumn::make('vacancy_type_classification.name')
->label(__('strings.models.vacancy_type_classification.single')),
Daniel Plomp
Daniel Plomp15mo ago
Which is okay for now. Would it be possible to create a custom view when I want to add records to that table? I think it is just associating some records? This would be the selection screen. First dropdown to filter the checkboxlist.
Daniel Plomp
Daniel Plomp15mo ago
When you select one or more items it should insert that result into the vacancy_classifications table. I'm not sure how to do this...
Unknown User
Unknown User15mo ago
Message Not Public
Sign In & Join Server To View
Hiz
Hiz15mo ago
You can maybe use a table action on the relation manager which shows a custom form within a modal: https://filamentphp.com/docs/2.x/tables/actions#custom-forms And perform your logic of associating the selected records
Filament
Actions - Table Builder - Filament
The elegant TALL stack table builder for Laravel artisans.
Daniel Plomp
Daniel Plomp15mo ago
Hi @.hiz Thanks for your suggestion. I find it difficult to understand how to create a form and show it from a Table Action. It is not describer (I think) in the docs. You have an example maybe/ ?
Hiz
Hiz15mo ago
My bad for the late response . In the file of your relation manger you can add your actions with a form to your headerActions() function
public static function table(Table $table): Table
{
return $table
->columns([
// Your columns
])
->filters([

])
->headerActions([
Action::make('test')
->action(function (User $record, array $data): void {
$record->author()->associate($data['authorId']);
$record->save();
})
->form([
Forms\Components\TextInput::make('name'),
Forms\Components\Toggle::make('active'),
])
]);

}
public static function table(Table $table): Table
{
return $table
->columns([
// Your columns
])
->filters([

])
->headerActions([
Action::make('test')
->action(function (User $record, array $data): void {
$record->author()->associate($data['authorId']);
$record->save();
})
->form([
Forms\Components\TextInput::make('name'),
Forms\Components\Toggle::make('active'),
])
]);

}