F
Filament16mo ago
Samer

how dynamically add form text Input or spatieTag into resource based on non related model

Hi , the scenario is I've spatietag but i've added TagsTypes as new model / table and added tags_type_id to tags and its working fine as i've resource to create types and save models/resourcesse which should show /use this type in pivot table (reporting_tags_model) and another resource to create tags in specific type. now my problem is in other resource lets name it transactionResource , in this transaction resource i need to add SpatiTag or even normal textInput to be created dynamically for each Tag Types that load them from pivot table ( table (reporting_tags_model which have tag_type_id and the model_name )) as if i added 5 tags types for transaction model i need 5 inputs in my transactions resource.
Solution:
In the form, it'll probably look like this: ```php $tagInputs = []; foreach ($tagTypes as $type) {...
Jump to solution
27 Replies
Patrick Boivin
Patrick Boivin16mo ago
Not sure if I'm missing something but I get a feeling that a Repeater field might be a better choice for your problem
Samer
SamerOP16mo ago
Hi @pboivin yes I agree , but I'm not sure how to pass that to repeater , as there is no direct relationship between the current record of the resource to the tags types ,the relationship is between the resource record and the tags but not the tags types So I was looking for a way to loop into the types and pass it to a repeater or find a way to do a function to loop into the types and create array and then add it to somehow to form arrwy
Patrick Boivin
Patrick Boivin16mo ago
Can you simplify your problem for me? You want to let users add tags to a resource and then for each tag, they can select a type?
Samer
SamerOP16mo ago
No , basically users can create tagng type for example a type called Project tags , then in that in tags he can create project 1 and project 2 as tags and they will both have tag type as Project , Now they user can dynamically in taging type creation edit resources and select which model to be used for by this taging type , so if in taging type Project user decided he want use project taging only in a resource called invoices then it will dynamically add input into the that resources
Samer
SamerOP16mo ago
Samer
SamerOP16mo ago
So when user go to enter or edit invoice he should see feild or spatietag field to select user project 1 or 2
Patrick Boivin
Patrick Boivin16mo ago
Ok, makes sense So your issue is in this Tags Types page? Or in the resource itself?
Samer
SamerOP16mo ago
Yes , if type wasn't dynamic I could put allot of them and hide the one I want dynamically , but the the issue is user can create unlimited types , like analys by project , by department and whatever
Patrick Boivin
Patrick Boivin16mo ago
Sure, but the issue you're having now, is it related to your screenshot here 👆 ?
Samer
SamerOP16mo ago
Oh sorry , I just send to explain , my issue is no the resource I want to show the tags in
Patrick Boivin
Patrick Boivin16mo ago
Ok... so I can share some thoughts, but I don't think I have a perfect solution
Samer
SamerOP16mo ago
no problem 🙂 just want to have a direction , as I'm completely new to this
Patrick Boivin
Patrick Boivin16mo ago
1. I think on this Tag Types page (above), I would probably use a Realation Manager instead, to attach the models to the types. I think it would remove a bit of custom code. 2. In your Resource Edit page, I think you'll be able to use the regular Tags input... but you'll need to customize the query to only allow valid tags for the current record type (if that makes any sense...)
Samer
SamerOP16mo ago
,ok for point #2 lets say this invoiceResource have like 3 tags type should be attached to each invoice, for example each invoice should be attached to A Project tag , A department tag and a user Tag , so in that Create/Edit in invoice Resource we need to dynamically have 3 input fields
Patrick Boivin
Patrick Boivin16mo ago
Ah ok, I missed a step here I get what you're saying about dynamic inputs I'm not completely sure but I get the feeling that you'll need to handle the save/update on the dynamic tags in a lifecycle method, like afterSave()
Samer
SamerOP16mo ago
so i can do something like function in hooks function { TagsTypeModel::All() ; foreach each tagType { SpatiTaginput::make() } } ?
Patrick Boivin
Patrick Boivin16mo ago
No, sorry. The hook will be to save the values in the DB. I'm not sure though, I think you'll need to explore this a bit.
Solution
Patrick Boivin
Patrick Boivin16mo ago
In the form, it'll probably look like this:
$tagInputs = [];

foreach ($tagTypes as $type) {
$tagsInput[] = SpatieTagInput::make(/* make a unique field name from $type */);
}

return $form
->schema([
...$tagInputs,
// other fields
])
$tagInputs = [];

foreach ($tagTypes as $type) {
$tagsInput[] = SpatieTagInput::make(/* make a unique field name from $type */);
}

return $form
->schema([
...$tagInputs,
// other fields
])
Patrick Boivin
Patrick Boivin16mo ago
(just to give you a rough idea)
Samer
SamerOP16mo ago
Yes , Thanks , i'll explore this , Thanks for your time Hi @pboivin Thanks for the tips, I managed to get it working using what you suggested i did two arrays one for normal inputs and i copied the form schema to it,and one array filled from the loop to get the fields dynamically then i pass them both with array merge to form schema.
$DynamicInputs = [];
$AllowedTagsTypes = reportingTagsModel::with('ReportingTagsTypes')->where('taggable_type',self::$model)->get();

foreach ($AllowedTagsTypes as $Tagtype) {
$DynamicInputs[] = SpatieTagsInput::make('tags')->label($Tagtype->ReportingTagsTypes->name)->helperText($Tagtype->taggable_type)->columnSpanFull();
}

$DynamicInputs = [];
$AllowedTagsTypes = reportingTagsModel::with('ReportingTagsTypes')->where('taggable_type',self::$model)->get();

foreach ($AllowedTagsTypes as $Tagtype) {
$DynamicInputs[] = SpatieTagsInput::make('tags')->label($Tagtype->ReportingTagsTypes->name)->helperText($Tagtype->taggable_type)->columnSpanFull();
}

NormalInputs = [
TextInput::make('code')
->required(),
...,]
NormalInputs = [
TextInput::make('code')
->required(),
...,]
then
return $form->schema(array_merge($NormalInputs,$DynamicInputs));
return $form->schema(array_merge($NormalInputs,$DynamicInputs));
Samer
SamerOP16mo ago
Samer
SamerOP16mo ago
now i need to work on the tags and saving them 😀
Patrick Boivin
Patrick Boivin16mo ago
@sameraj This looks good! I think all you're missing is a unique name for each Tags input. In a hook like afterSave(), you can pull the information from $this->data and save into the appropriate relationships.
Samer
SamerOP16mo ago
Oh , thanks , i think this will work , I'll try it 🙂 the weird thing with dynamic names for example
SpatieTagsInput::make($Tagtype->ReportingTagsTypes->id)
->type($Tagtype->ReportingTagsTypes->id)
SpatieTagsInput::make($Tagtype->ReportingTagsTypes->id)
->type($Tagtype->ReportingTagsTypes->id)
it saves correctly without doing any custom saving, but I need to find a way to be able to fill it on edit to fill the input with the current value. not sure if i need to change this
$tags = $record->load('tags')->tagsWithType($type);
$tags = $record->load('tags')->tagsWithType($type);
in
class SpatieTagsInput extends TagsInput
class SpatieTagsInput extends TagsInput
Patrick Boivin
Patrick Boivin16mo ago
Not completely sure but I think the fill can be done with afterStateHydrated() on the field
Samer
SamerOP16mo ago
i've did little bit of change, I'm using select now instead of SpatietagsInput , and saving with afterSAve() and refill with AfterFill and its working now .
protected function afterSave(): void
{

$AllowedTagsTypes = reportingTagsModel::with('ReportingTagsTypes')->where('taggable_type',$this->getModel())->get();
$TagsArray = [];

foreach ($AllowedTagsTypes as $Tagtype)
{
if (!empty($this->data[$Tagtype->ReportingTagsTypes->name]))
{
$TagsArray [] = $this->data[$Tagtype->ReportingTagsTypes->name];
}
}

$this->getRecord()->syncTags($TagsArray);
}

protected function afterFill()
{

$AllowedTagsTypes = reportingTagsModel::with('ReportingTagsTypes')->where('taggable_type',$this->getModel())->get();

foreach ($AllowedTagsTypes as $Tagtype)
{

$CurrenTags = $this->record->tags()->with('reportingTagsType')->where('tag_type_id',$Tagtype->ReportingTagsTypes->id)->get();

if (!empty($CurrenTags['0']))
{
$this->data[$Tagtype->ReportingTagsTypes->name] = $CurrenTags['0']->name;

}

}


}
protected function afterSave(): void
{

$AllowedTagsTypes = reportingTagsModel::with('ReportingTagsTypes')->where('taggable_type',$this->getModel())->get();
$TagsArray = [];

foreach ($AllowedTagsTypes as $Tagtype)
{
if (!empty($this->data[$Tagtype->ReportingTagsTypes->name]))
{
$TagsArray [] = $this->data[$Tagtype->ReportingTagsTypes->name];
}
}

$this->getRecord()->syncTags($TagsArray);
}

protected function afterFill()
{

$AllowedTagsTypes = reportingTagsModel::with('ReportingTagsTypes')->where('taggable_type',$this->getModel())->get();

foreach ($AllowedTagsTypes as $Tagtype)
{

$CurrenTags = $this->record->tags()->with('reportingTagsType')->where('tag_type_id',$Tagtype->ReportingTagsTypes->id)->get();

if (!empty($CurrenTags['0']))
{
$this->data[$Tagtype->ReportingTagsTypes->name] = $CurrenTags['0']->name;

}

}


}
Want results from more Discord servers?
Add your server