javascriptjquerysymfonysymfony-formsformcollection

Nested form Collection in symfony 2


I have a Form which includes a collection type field, inside the collection type field there is one more collection type field. I have to add nested form fields in the twig but I am unable to populate the form fields and wasn't able to find a example where it shows, how nested fields can be populated with JQuery.

First form class :

class SurveyType extends AbstractType
   {
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       $builder->add(
                'questiongroups',
                CollectionType::class,
                [
                    'entry_type' => QuestionGroupType::class,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'entry_options' => [
                         'submitOption' => $options['submitOption']
                    ]
                ]
            );
    }

Second form class which have another collection type field :

class QuestionGroupType extends AbstractType
   {
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       $builder->add(
                'questions',
                CollectionType::class,
                [
                    'entry_type' => QuestionType::class,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'entry_options' => [
                         'submitOption' => $options['submitOption']
                    ],
                    'prototype_name' => '__que__'
                ]
            );
    }

On twig I its like this:


                           <ul id="questiongroups-field-list" data-prototype-question="{{ form_widget(form.questiongroups.vars.prototype.children['questions'].vars.prototype)|e }}"
                        data-prototype="{{ form_widget(form.questiongroups.vars.prototype)|e}}"
                        data-widget-tags="{{'<li></li>'|e}}">

My Jquery for Populating the fields:

$(document).on('click', '.add-another-collection-widget', function(e){
                var list = $($(this).attr('data-list'));
                var counter = list.data('widget-counter') | list.children().length;

                var newWidget = list.attr('data-prototype');
                newWidget = newWidget.replace(/__name__/g, counter);
                console.log(newWidget);
                counter++;

                list.data('widget-counter', counter);

                var newElem = jQuery(list.attr('data-widget-tags')).html(newWidget);
                newElem.appendTo(list);
                addTagFormDeleteLink(newElem);
            });

            function addTagFormDeleteLink($tagFormLi) {
                var $addQuestionButton = $('<button class="button" type="button">Add Question</button>');
                var $removeFormButton = $('<button class="alert button" type="button">Delete Group</button>');
                $tagFormLi.append($addQuestionButton);
                $tagFormLi.append($removeFormButton);
                $removeFormButton.on('click', function(e) {
                    // remove the li for the tag form
                    $tagFormLi.remove();
                });

                $addQuestionButton.on('click', function(){
                    var list = $('#questiongroups-field-list');
                    var counter = list.data('widget-counter') | list.children().length;
                    var newWidget = list.attr('data-prototype-question');
                    newWidget = newWidget.replace(/__name__/g, counter);
                    counter++;

                    list.data('widget-counter', counter);
                    $tagFormLi.append(newWidget);
                });
            }

Solution

  • After carefully going through the prototype variables. This is how I have modified the code of Single form collection into nested form collection: Prototye Field Changes:

    <ul id="questiongroups-field-list" data-prototype-question = "{{ form_widget(form.questiongroups.vars.prototype.children['questions'].vars.prototype)|e }}"
                        data-prototype="{{ form_widget(form.questiongroups.vars.prototype)|e}}"
                        data-widget-tags="{{'<li></li>'|e}}" data-tag-list = "{{ '<ul class="question-list"></ul>' |e}}">
    

    Below is the Jquery Code:

    $(document).on('click', '.add-questiongroup[data-target]', function(event) {
                var collectionHolder = $($(this).attr('data-target'));
    
                if (!collectionHolder.attr('data-counter')) {
                    collectionHolder.attr('data-counter', collectionHolder.children().length);
                }
    
                var prototype = collectionHolder.attr('data-prototype');
                var form = prototype.replace(/__name__/g, collectionHolder.attr('data-counter'));
    
                newWidget = $(collectionHolder.attr('data-widget-tags')).html(form);
                newWidget.append(collectionHolder.attr('data-tag-list'));
    
                collectionHolder.attr('data-counter', Number(collectionHolder.attr('data-counter')) + 1);
                collectionHolder.append(newWidget);
    
                var questionPrototype = collectionHolder.attr('data-prototype-question');
                var counter = collectionHolder.attr('data-counter');
    
                newWidget.attr('data-counter', counter);
                addTagFormDeleteLink(newWidget);
                $('.option-min, .option-max').parent().hide();
                event && event.preventDefault();
            });
    
            function addTagFormDeleteLink(newWidget) {
                $removeFormButton = $('<button type="button" class="alert button">Delete Group</button>');
                $addQuestionButton = $('<button type="button" class="button">Add Question</button><br>');
                $removeQuestion = $('<button type="button" class="alert button deleteQuebtn">Delete Question</button>');
                newWidget.append($addQuestionButton);
                newWidget.append($removeFormButton);
    
                $removeFormButton.on('click', function(e) {
                    newWidget.remove();
                });
    
                $addQuestionButton.on('click', function(e){
                    $holder = $('#questiongroups-field-list');
                    $question = $holder.attr('data-prototype-question');
                    $questionHolder = newWidget.find('ul');
    
                    var counter = $questionHolder.children().length;
                    var form = $question.replace(/__name__/g, $holder.attr('data-counter')-1).replace(/__que__/g, counter++);
                    var newQuestion = $($holder.attr('data-widget-tags')).html(form);
    
                    $questionHolder.append(newQuestion);
    
                });
            }