Search code examples
jquerysymfonyajaxformsymfony-3.1

Symfony3 Ajax Form Add Extra Field


AdminBundle\Form\CoreForm.php:

class CoreForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        /**
        Ajax Call : onSubmitAdd
        */
        $builder->add('set_core_doctrine_metadata_type', ChoiceType::class, array(
            'label' => 'Doctrine Metadata Cache Driver',
            'choices' => $this->getDoctrineAccelerator(),
            'empty_data' => 'array',
            'choice_translation_domain' => false,
            'attr' => array(
                'onSubmitAdd' => 'set_core_doctrine_metadata_host|set_core_doctrine_metadata_port'
            )
        ))

        /**
        Ajax Response : onSubmitAdd
        */
        $doctrineModify = function (FormInterface $form){
            $metaDataDriver = $form->get('set_core_doctrine_metadata_type')->getData();

            if (!$form->isValid()) {
                if ($metaDataDriver == 'memcache' || $metaDataDriver == 'memcached'){
                    $form->add('set_core_doctrine_metadata_host', TextType::class, array(
                        'label' => 'Doctrine Metadata Cache Host',
                    ))
                    ->add('set_core_doctrine_metadata_port', IntegerType::class, array(
                        'label' => 'Doctrine Metadata Cache Port',
                    ));
                }
            }
        };

        $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use ($doctrineModify){
            $form = $event->getForm();
            $doctrineModify($form);
        });
    }
}

Form Type: Form working smoothly. But it does not allow new field.

jQuery Ajax Code:

$(document).on('change', '[onSubmitAdd]', function () {
    // Get Form
    form = $(this).closest('form');

    // Send Data
    var data = {};
    data[$(this).attr('name')] = $(this).val();

    // Html Block
    formGroup = $(this).closest('.form-group');
    getFormGroup = $(this).attr('onSubmitAdd');
    getFormGroup = getFormGroup.split('|');

    $.ajax({
        url: form.attr('action'),
        type: form.attr('method'),
        data: data,
        success: function (data) {
            addContent = "";

            // Get Items
            $.each(getFormGroup, function (index, item) {
                dt = $(data.content.body).find('.' + item).html();
                if (typeof dt != 'undefined'){
                    addContent = addContent + '<div class="form-group">'+ dt +'</div>';
                }
            });

            // Replace or Add
            if (formGroup.next().hasClass('onSubmitAdded')){
                formGroup.next().html(addContent);
            } else {
                formGroup.after('<div class="onSubmitAdded">'+ addContent +'</div>');
            }
        }
    });
});

Problem: Ajax system is working smoothly. But when the form is submitted, the error code "This form should not contain extra fields"


Solution

  • To be able to accept the extra submitted choices, you have to add them in your form on the PRE_SUBMIT Event :

     class FooType extends AbstractType
     {
         public function buildForm(FormBuilderInterface $builder, array $options)
         {
             $builder
                 ->add('tag', ChoiceType::class, array('choices'=>array()))
             ;
    
             $builder->addEventListener(
                 FormEvents::PRE_SUBMIT,
                 function(FormEvent $event){
                     // Get the parent form
                     $form = $event->getForm();
    
                     // Get the data for the choice field
                     $data = $event->getData()['tag'];
    
                     // Collect the new choices
                     $choices = array();
    
                     if(is_array($data)){
                         foreach($data as $choice){
                             $choices[$choice] = $choice;
                         }
                     }
                     else{
                         $choices[$data] = $data;
                     }
    
                     // Add the field again, with the new choices :
                     $form->add('tag', ChoiceType::class, array('choices'=>$choices));
                 }
             );
         }
     }
    

    To avoid "Notice: Array to string conversion" Think to copy all field array parameters in new field in $form, for example, if you have 'multiple' => true in $builder 'tag' put it in $form 'tag' too