Recherche…


Comment étendre ChoiceType, EntityType et DocumentType pour charger des choix avec AJAX.

Dans Symfony, le ChoiceType intégré (et l’EntityType ou DocumentType l’extendant), fonctionnent de manière fondamentale avec une liste de choix constante.

Si vous voulez le faire fonctionner avec les appels ajax, vous devez les modifier pour accepter les choix supplémentaires cumulés.

  • Comment commencer avec une liste de choix vide?

    Lorsque vous créez votre formulaire, définissez simplement l'option choices sur un array() vide array() :

     namespace AppBundle\Form;
    
     use Symfony\Component\Form\AbstractType;
    
     use Symfony\Component\Form\FormBuilderInterface;
    
     use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
    
     class FooType extends AbstractType
     {
         public function buildForm(FormBuilderInterface $builder, array $options)
         {
             $builder
                 ->add('tag', ChoiceType::class, array('choices'=>array()));
         }
     }
    

    Vous obtiendrez donc une entrée de sélection vide, sans choix. Cette solution fonctionne pour ChoiceType et tous ses enfants (EntityType, DocumentType, ...).

  • Comment accepter les nouveaux choix soumis :

    Pour accepter les nouveaux choix, vous devez les rendre disponibles dans la liste de sélection des champs de formulaire. Vous pouvez modifier votre champ de formulaire en fonction des données soumises avec l'événement FormEvent :: PRE_SUBMIT.

    Cet exemple montre comment le faire avec un ChoiceType de base:

     namespace AppBundle\Form;
    
     use Symfony\Component\Form\AbstractType;
    
     use Symfony\Component\Form\FormBuilderInterface;
    
     use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
    
     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));
                 }
             );
         }
     }
    

    Vos choix soumis sont maintenant des choix autorisés et la validation intégrée de Symfony ChoiceType ne les rejettera plus.

    Si vous souhaitez faire la même chose avec un enfant ChoiceType (EntityType, DocumentType, ...), vous devez injecter entityManager ou le documentManager et effectuer la transformation de données lors du remplissage des nouveaux choix.

Remplir un champ de sélection en fonction de la valeur autre.

Cet exemple montre comment modifier les choix autorisés dans un champ de sélection de sous-catégorie en fonction de la valeur du champ de sélection de catégorie. Pour ce faire, vous devez rendre vos choix de sous-catégories dynamiques à la fois pour le client et pour le serveur.

1. Rendre le formulaire dynamique du côté client pour les interactions d'affichage / utilisateur

Exemple de formulaire dynamique côté client (en utilisant Javascript / JQuery):

    $('#category').change(function(){
        switch($(this).val()){
            case '1': // If category == '1'
                var choice = {
                    'choice1_1':'1_1',
                    'choice1_2':'1_2',
                    'choice1_3':'1_3',
                };
            break;
            case '2': // If category == '2'
                var choice = {
                    'choice2_1':'2_1',
                    'choice2_2':'2_2',
                    'choice2_3':'2_3',
                };
            break;
            case '3': // If category == '3'
                var choice = {
                    'choice3_1':'3_1',
                    'choice3_2':'3_2',
                    'choice3_3':'3_3',
                };        
            break;
        }
        
        var $subCategorySelect = $('#subCategory');
        
        $subCategorySelect.empty();
        $.each(choice, function(key, value) {
            $subCategorySelect.append($('<option></option>')).attr('value',value).text(key);
        });
    });

Bien sûr, vous pouvez choisir parmi un appel AJAX. Ce n'est pas le but de cet exemple.

2. Rendre le formulaire dynamique du côté serveur pour l'initialisation / validation

Exemple de formulaire dynamique côté serveur:

    namespace AppBundle\Form;

    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;

    use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

    use Symfony\Component\Form\FormEvent;
    use Symfony\Component\Form\FormEvents;

    class MyBaseFormType extends AbstractType
    {
        /**
         * @param FormBuilderInterface $builder
         * @param array $options
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('category',ChoiceType::class,array('choices'=>array(
                        'choice1'=>'1',
                        'choice2'=>'2',
                        'choice3'=>'3',
                    )))
            ;
            
            $addSubCategoryListener = function(FormEvent $event){
                $form = $event->getForm();
                $data = $event->getData();
                
                switch($data['category']){
                    case '1': // If category == '1'
                        $choices = array(
                            'choice1_1'=>'1_1',
                            'choice1_2'=>'1_2',
                            'choice1_3'=>'1_3',
                        );
                    break;
                    case '2': // If category == '2'
                        $choices = array(
                            'choice2_1'=>'2_1',
                            'choice2_2'=>'2_2',
                            'choice2_3'=>'2_3',
                        );                        
                    break;
                    case '3': // If category == '3'
                        $choices = array(
                            'choice3_1'=>'3_1',
                            'choice3_2'=>'3_2',
                            'choice3_3'=>'3_3',
                        );                        
                    break;
                }
                
                $form->add('subCategory',ChoiceType::class,array('choices'=>$choices));
            };
            
            // This listener will adapt the form with the data passed to the form during construction :
            $builder->addEventListener(FormEvents::PRE_SET_DATA, $addSubCategoryListener);
            
            // This listener will adapt the form with the submitted data :
            $builder->addEventListener(FormEvents::PRE_SUBMIT, $addSubCategoryListener);
        }
    }


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow