Dynamically generating Nova Select's 'dependsOn()' method for create form
I'm working on building a support / ticket system where users can submit tickets to the helpdesk and based on the ticket types and system settings, the ticket will be automatically assigned to a specific team. But first, I need to get the creation form for the ticket to work.
A ticket model belongs to a TicketType model. The TicketType is a recursive / self referential model where it can belong to another TicketType, or it can have many child TicketTypes.
TicketType model relationships:
public function children(): HasMany
{
return $this->hasMany(
related: TicketType::class,
foreignKey: 'parent_id'
);
}
public function parent(): BelongsTo
{
return $this->belongsTo(
related: TicketType::class,
foreignKey: 'parent_id'
);
}
public function tickets(): HasMany
{
return $this->hasMany(Ticket::class);
}
Now, because the ticket type can reference itself, what I want to do is have a Select field for the 'root' types, that is, the types that do not have a parent type. When a user selects one of the root type options, a new select field should appear with the children of the currently selected root type as the options.
That is, if root types are [A, B, C] and A has children [1, 2, 3], then when the user selects "A" from the Select field, the new Select field that appears under it will show the options [1,2,3], and this would continue recursively until the user selects a final (nth) subtype.
The way I was handling this was by creating a method that returns an array of Select fields and calls on itself to generate the fields using the parent field's information. But when I go to test it, and I select an option I know has children, the child selects never appear, and I cannot figure out why.
Any help would be greatly appreciated!
protected function getTypes(?array $fields = null, ?string $parentFieldName = null, ?int $parentId = null)
{
if (!isset($fields)) {
$fields = [];
}
if (is_null($parentFieldName)) {
// Get root ticket types with their nested children
$rootTypes = TicketTypeModel::selectGroups();
// Convert to array for the Select field options
$rootOptions = $rootTypes->pluck('name', 'id')->toArray();
// Create the root Select field
$rootFieldName = 'root_ticket_type_id';
$fields[] = Select::make('Ticket Type', $rootFieldName)
->options($rootOptions)
->displayUsingLabels()
->rules('required')
->fillUsing(function (
$request,
$model,
$attribute,
$requestAttribute) {
$model->{$attribute} = $request->input($requestAttribute);
})->size('w-1/2');
// Recursively create fields for children
$rootTypes->each(function ($type) use (&$fields, $rootFieldName) {
$this->getTypes($fields, $rootFieldName, $type->id);
});
} else {
// Fetch children based on parent ID
$children = TicketTypeModel::where('parent_id', $parentId)->get();
if ($children->isNotEmpty()) {
$childOptions = $children->pluck('name', 'id')->toArray();
$childFieldName = 'ticket_type_' . $parentId;
$fields[] = Select::make('Ticket Subtype', $childFieldName)
->options($childOptions)
->displayUsingLabels()
->hide()
->dependsOn([$parentFieldName], function (
Select $field,
NovaRequest $request,
FormData $formData ) use ($parentFieldName, $parentId)
{
if ($formData->select($parentFieldName) == $parentId) {
$field->show()->rules('required');
}
})
->size('w-1/2');
// Recursively create fields for children
$children->each(function ($child) use (&$fields, $childFieldName) {
$this->getTypes($fields, $childFieldName, $child->id);
});
}
}
return $fields;
}
Please or to participate in this conversation.