I've been working through the Symfony 3 tutorial on embedding a collection of forms, and I want to extend the idea to extra nested levels. I had a look around, and there are partial answers for Symfony 2, but nothing comprehensive (and nothing for 3).
If we take the tutorials Task has many Tag example, how would I code it so it extends to: Task has many Tag has many SubTag?
So far I think I understand the Form classes:
Task:
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description');
$builder->add('tags', CollectionType::class, array(
'entry_type' => TagType::class,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Task',
));
}
}
Tag:
class TagType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('sub_tags', CollectionType::class, array(
'entry_type' => SubTagType::class,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Tag',
));
}
}
SubTag:
class SubTagType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\SubTag',
));
}
}
And the basic Twig class:
{{ form_start(form) }}
{# render the task's only field: description #}
{{ form_row(form.description) }}
<h3>Tags</h3>
<ul class="tags">
{# iterate over each existing tag and render its only field: name #}
{% for tag in form.tags %}
<li>{{ form_row(tag.name) }}</li>
{% for sub_tag in tag.sub_tags %}
<li>{{ form_row(sub_tag.name) }}</li>
{% endfor %}
{% endfor %}
</ul>
{{ form_end(form) }}
But it's at this point I'm unsure of how the prototype and javascript will work. Could somebody explain how I'd take this next step? Is this even the right approach?
My first thought is that if we're doing additional levels, it might be smart to generalize the JS for any number of levels, since the tutorial uses very JS that can only work on a single level.
The closest working code I can find is this stack overflow answer here. However, it doesn't appear to work as described, and Im having trouble working out exactly what's wrong.