Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Symfony2] Une liste déroulante qui dépendant d'une autre

Sujet résolu
28 mars 2012 à 13:14:54

Bonjour, voila je travail sur un petit projet avec symfony2, j'aimerais créer une liste déroulante qui dépend d'une autre, le deux remplies dynamiquement à partir de la base. Par exemple en choisissant une Entreprise (1ère liste), la 2ème serait chargée automatiquement par les personnes appartenant à l'entreprise.

J'ai créé le formulaire, je suis capable de remplir les listes séparément mais l'une en fonction de l'autre, si vous pouvez m'aider je serais reconnaissant... ^^
  • Partager sur Facebook
  • Partager sur Twitter
28 mars 2012 à 13:33:42

BOnjour,

Est il génant que ta page ce recharge ?
Si oui je te ocnseil vivement de t'orienter vers de l'ajax.

Dans l'attente de ta réponse.
  • Partager sur Facebook
  • Partager sur Twitter
Albert Einstein disait; une question parfois me laisse perplexe: est ce moi, ou les autres qui sommes fou?
28 mars 2012 à 13:43:44

Merci pour la réponse, en tant que débutant dans symfony, non ce n'est pas génant. Je passerai à ajax par la suite, d'abord faut que ça fonctionne...
  • Partager sur Facebook
  • Partager sur Twitter
28 mars 2012 à 13:53:38

J'ai pensé à Ajax aussi, sais-tu quel est le but d'Ajax au moins ?
  • Partager sur Facebook
  • Partager sur Twitter
Site : https://gokan-ekinci.appspot.com | Miagiste en recherche d'emploi | Profil [Dév. Java SE & EE | Dév. QlikView]
28 mars 2012 à 14:01:24

Oui je connais le but d'Ajax, enfin je crois : ne recharger qu'une partie de la page, celle qui nous intéresse. Seulement, je n'ai jamais bossé avec Ajax, encore moins Ajax+Symfony2...
  • Partager sur Facebook
  • Partager sur Twitter
29 mars 2012 à 17:01:06

Ca passe forcément par du JavaScript, mais pas forcément par de l'Ajax. Avec du pot peut-être y a-t'il un bundle qui permette cela directement(et construisant son propre JS), mais sinon tu peux le construire toi-même.

Si tu le construis, dans le principe tu dois faire une requête sur ta table de sous-catégories avec jointure sur celle des catégories, envoyer ça sur ton template twig, et entre des balises JavaScript, créer un tableau JS en itérant sur le résultat de la requête.
Du genre:
{% for subCategory in subCategories  %}
{
  arrayJS['{{subCategory.category.name}}']['{{subCategory.id}}'] = '{{ subCategory.name}}';
}
{% endfor %}

Ensuite, ce sera entièrement du JS: il te faudra gérer l'évènement, récupérer le nom du contenu sélectionné dans le menu option, puis faire une boucle for, afin de reconstituer la liste d'options du menu subCategory à la volée.
  • Partager sur Facebook
  • Partager sur Twitter
30 mars 2012 à 17:56:00

En gros, tu peux te faire un premier <select> des entreprises. Dans le 2nd <select#persons>, tu peux faire des <optgroup>, avec pour chaque opt group le nom de l'entreprise => les personnes. Tu fais
$(function () {
 var persons = $('#persons').html(); //select#persons
 var personsElem = $('#persons').empty(); //on vide l'élement au chargement de la page
 $('#entreprise').change(function () {
  var $this = $(this);
  var personsList = $(persons).find('[name="' + $this.html() + '"]'); //on trouve l'optgroup avec le name = l'entreprise
  personsElem.html(personsList.html()); //et on update
 });
});
  • Partager sur Facebook
  • Partager sur Twitter
4 avril 2012 à 11:33:23

Merci pour vos réponses, je vais essayer vos propositions. Merci :)
  • Partager sur Facebook
  • Partager sur Twitter
22 juin 2012 à 15:33:06

Je me permet de relancer le sujet , j'essaye également de remplir une liste déroulante en fonction d'une autre mais je bloque ... J'ai créé un premier formulaire :

<?php class LoadVendorsType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('name', 'entity', array('label' => 'vendors.name', 
                                          'class' => 'DD\TechnoServeyBundle\Entity\vendor', 
                                          'property' => 'name'))
        ;
        
        $builder
            ->add('products', 'choice', array("choices" => array('*****')))
        ;
    }

    public function getName()
    {
        return 'dd_technoserveybundle_loadvendorstype'; // Name of the form
    }
    
    public function getDefaultOptions(array $options)
    {
    	return array('data_class' => 'DD\TechnoServeyBundle\Entity\vendor',);
    }
}


Dans un premier temps le select avec une entité à la clé et le second avec un choice.

Je le récupère dans la vue correctement. Ensuite pour savoir se que l'utilisateur choisi par rapport à la liste déroulante, j'utilise le JQuery ainsi qu'une requête AJAX pour l'envoyer au contrôleur :

function remplirProduct()
{
	var vendor = $("select.ChoiceVendorAdd option:selected").val();
	//alert(vendor);
	
	var vendor = $("select.ChoiceVendorSearch option:selected").val();
	//alert(vendor);
	
	$(".ChoiceVendorAdd").change(function() {
		
		var vendor = $("select.ChoiceVendorAdd option:selected").val();
		//alert(vendor);
		var DATA = 'id=' + vendor;
        $.ajax({
            type: "POST",
            url:  "http://localhost/ProjetDiData/TechnoServey/web/app_dev.php/rempliproduct",
            data: DATA,
            success: function(response)
            {
                /*$('.ChoiceProduct').find("option").remove();
                $.each(response, function(i, item) 
                {
                    $('.ChoiceProduct').append(new Option(item, i));
                });*/
            	alert("Data Saved:" + response);
            }
        });
	});  
}
(Concernant l'url je l'ai mi en dur puisque j'ai un soucis avec "path")

Une fois dans le contrôleur j'ai récupère bien la valeur, je détecte bien si c'est une requête Ajax. Maintenant mon soucis commence ...

Voici mon contrôleur :
<?php public function rempliProductAction()
    {

    	$request = $this->getRequest();
        $em = $this->getDoctrine()->getEntityManager();
        
        if($request->isXmlHttpRequest()) // pour vérifier la présence d'une requete Ajax
        {
            $vendor = '';
            $vendor = $request->request->get('id');
            
            
            if ($vendor != null)
            {          
            	$products = $this->getDoctrine()
            	                 ->getEntityManager()
            	                 ->getRepository('DDTechnoServeyBundle:product')
            	                 ->getProducts($vendor);
            	                 
            	$tabProducts = array();
            	$i = 0;
            	                 
            	//return new Response($products);          
            	       
            	foreach ($products as $product)
            	{
            		$tabProducts[$i][name] = $product->getName();
            		$i++;
            	}
            	
	            $response = new Response();
	            $data = json_encode($product); // c'est pour formater la réponse de la requete en format que jquery va comprendre
	            $response->headers->set('Content-Type', 'application/json');
	            $response->setContent($data);
	            return new Response($response);
	            return $response;
            }
            else 
            {
            	$products = $em->getRepository('DDTechnoServeyBundle:product')->findAll();
            }
            
            return $this->render('DDTechnoServeyBundle:Add:add.html.twig', array('vendors' => $vendors,
    	                                                                         'products' => $products,
    	                                                                         'productVersions' => $productVersions,
    	                                                                         'formLoadVendor' => $formLoadVendor->createView(),
    	                                                                         'formAddVendor' => $formAddVendor->createView())); 
        }
        
        return new Response("Nonnn ....");
    }


J'ai bien mis ma requête dans le repository :
<?php class productRepository extends EntityRepository
{
	public function getProducts($id)
	{
		$queryBuilder = $this->createQueryBuilder('a');
		
		$queryBuilder->where('a.vendor LIKE :vendor')
		             ->setParameter('vendor', 1)
		             ->join('a.vendor', 'p')
		             ->addSelect('p');
		             
		return $queryBuilder->getQuery()
		                    ->getResult();
	}
}

Pour le paramètre j'ai préféré mettre 1 pour être en dur, pour regarder si cela fonctionne. Mais cela ne fonctionne pas =S J'ai vraiment du mal la ...
Et concernant la vue, je n'ai rien à par ma première liste déroulante et les petites étoiles dans la deuxième =(
  • Partager sur Facebook
  • Partager sur Twitter
25 juin 2012 à 13:40:30

J'ai résolu mon problème. Je me permet de partager mon code pour aider d'autres personnes si nécessaire.

Pour commencer voici ma vue :

{{ form_widget(formLoadVendor.name, { 'attr': {'class': 'ChoiceVendorAdd'} }) }}
{{ form_widget(formLoadProduct.name, { 'attr': {'class': 'ChoiceProductAdd'} }) }}


Au préalable j'ai déclaré mes formulaires, je ne met pas les deux mais juste un : (C'est pratiquement les mêmes )



<?php

namespace DD\TechnoServeyBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class LoadVendorsType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('name', 'entity', array('class' => 'DD\TechnoServeyBundle\Entity\vendor', 
                                          'property' => 'name'))
        ;
    }

    public function getName()
    {
        return 'dd_technoserveybundle_loadvendorstype'; // Name of the form
    }
    
    public function getDefaultOptions(array $options)
    {
    	return array('data_class' => 'DD\TechnoServeyBundle\Entity\vendor',);
    }
}


Ensuite pour gérer le choix de l'utilisateur voici ma partie de JavaScipt :

function remplirProductSearch()
{	
	$(".ChoiceVendorSearch").change(function() {
		
		var vendor = $("select.ChoiceVendorSearch option:selected").val();
		var DATA = 'id=' + vendor;
		
		$.ajax({
	        type: "POST",
	        dataType: 'json',
	        url:  "/ProjetDiData/TechnoServey/web/app_dev.php/rempliproduct",
	        data: DATA,
	        success: function(msg)
	        {
	            $.each(msg, function(index, product) 
	            {
	            	$('.ChoiceProductSearch').html('');
	            	$('.ChoiceProductSearch').append('<option value="'+ product.id +'" selected="selected"> '+ product[0].name +' </option>');
	            });
	        }
	    });
	});  
}


Mon contrôleur qui va traiter la requête AJAX :

<?php public function rempliProductAction()
    {
		
    	$request = $this->getRequest();
        
        if($request->isXmlHttpRequest()) // pour vérifier la présence d'une requete Ajax
        {
            $idVendor = $request->request->get('id');
            
            if ($idVendor != null)
            {    
            	$product = $this->getDoctrine()
            	                ->getEntityManager()
            	                ->getRepository('DDTechnoServeyBundle:product')
            	                ->getProducts($idVendor);
            	                
            	$response = new Response();
		        $product = json_encode(array('product' => $product));
		        $response->headers->set('Content-Type', 'application/json');
		        $response->setContent($product);
		        return $response;
            }
        }
        
        return new Response("Nonnn ....");
    }


J'espère ne rien avoir oublié, si besoin n'hésiter pas.

Cordialement,

Tomii
  • Partager sur Facebook
  • Partager sur Twitter
6 août 2012 à 12:55:49

Salut Tomii,
pour le Repository tu as garder le même que dans ton message précédent ?
Pour le controlleur "rempliProduct" c'est un controlleur uniquement dédié à ça ou il peut etre utiliser avec d'autres function ?
et enfin pour "ChoiceVendorSearch" dans le JS ce champ n'est pas utiliser dans la vue ?

merci
  • Partager sur Facebook
  • Partager sur Twitter
6 août 2012 à 14:30:08

Citation : hm55


Salut Tomii,
pour le Repository tu as garder le même que dans ton message précédent ?



Salut hm55, non j'ai changé mon Repository, voici un bout si ca peut aider :

<?php
public function getProducts($id) //Using
	{
		$queryBuilder = $this->_em->createQueryBuilder();
		
		$queryBuilder->select('p')
		             ->from('DDTechnoSurveyBundle:product', 'p')
		             ->where('p.vendor = :vendor')
		             ->setParameter('vendor', $id)
		             ->orderBy('p.name', 'ASC')
		             ->groupBy('p.name');
		             
		return $queryBuilder->getQuery()
		                    ->getArrayResult();
	}


Citation : hm55

Pour le controlleur "rempliProduct" c'est un controlleur uniquement dédié à ça ou il peut etre utiliser avec d'autres function ?



Concernant le controlleur, la fonction tu peux l'appeler autant de fois que tu veux, après tout dépend de ce que tu veux faire.

Citation : hm55

et enfin pour "ChoiceVendorSearch" dans le JS ce champ n'est pas utiliser dans la vue ?



J'ai pas mis exactement le bon code, je cherchais la logique. "ChoiceVendorSearch" est une classe dans ma vue que j'utilise dans mon JS. Dans ton JS tu sélectionne soit une classe soit un ID. Tout dépend de ce que tu veux faire.
  • Partager sur Facebook
  • Partager sur Twitter
6 août 2012 à 15:58:21

Je ne sais pas se que tu as voulus faire, au cas où je te permet de reposter si tu as besoin ;)
  • Partager sur Facebook
  • Partager sur Twitter
6 août 2012 à 17:30:20

Merci ! erreur de manip :/
Je vais essayer de résumer mon problème par rapport à ce que tu as fait.
J'ai une interface d'admin de gestion de livre et dans ma gestion des pages j'ai 2 listes (une pour les livres et une pour les chapitres) j'arrive a afficher les livres et chapitres mais la ce sont tout les livres et chapitres donc il y a un problème !
1/ Au niveau du contrôleur il y a pas de soucis à mettre dans mon PageController la gestion en Ajax dans la requête ou je dois créer un contrôleur uniquement pour ça ?
2/ si non, alors peut etre as-tu deja ete confronter au meme soucis que moi (toutes les données s'affichent et pas en fonction du livre)
Voila mon JS (ya pas vraiment de différence avec le tien mais on sait jamais :))
<script type="text/javascript">

        $(".ChoiceLivre").change(function() {

        var vendor = $("select.ChoiceLivre option:selected").val();
        var DATA = 'id=' + vendor;

        $.ajax({
        type: "POST",
        dataType: 'json',
        url:  "{{ path('pages_c_u')}}",
        data: DATA,
        success: function(msg)
        {
        $.each(msg, function(index, chapitre)
        {
        $('.ChoiceChapitre').html('');
        $('.ChoiceChapitre').append('<option value="'+ chapitre.id +'" selected="selected"> '+ chapitre[0].name +' </option>');
        });
        }
        });
        });

    </script>


/**Gestion des requetes AJAX*/
    public function remplirChap()
    {
        $request = $this->getRequest();

        if($request->isXmlHttpRequest()) 
        {
            $idVendor = $request->request->get('id');

            if ($idVendor != null)
            {
                $chapitre= $this->getDoctrine()
                    ->getEntityManager()
                    ->getRepository('BTProjectBundle:chapitre')
                    ->getLivreWithChapitre($idVendor);

                $response = new Response();
                $chapitre = json_encode(array('chapitre' => $chapitre));
                $response->headers->set('Content-Type', 'application/json');
                $response->setContent($chapitre);
                return $response;
            }
        }
    }

Quand je regarde avec un outil de débogage pour le JS ça me retourne le code 200, mais ça renvoie également tout le HTML de la page.
ça fait quelques heures que je bloque la dessus donc si t'as la moindre idée je t'écoute :)
merci
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 10:40:23

1) Peut-tu me montrer ta requête "getLivreWithChapitre()" s'il te plaît ?

2) "$('.ChoiceChapitre').empty();" est recommandé à la place de "$('.ChoiceChapitre').html('');" (C'est un conseil que l'on m'a donné, qui mange moins de ressource ^^)

3) J'ai un seul contrôleur avec à l'intérieur toutes mes fonctions (Je ne sais pas si c'est la meilleur solution)

4) "url: "{{ path('pages_c_u')}}"," Est-ce que tu arrive bien dans le contrôleur ? J'ai également un soucis d'url. Winzou m'a lancé sur la piste d'un Bundle qui permet d'intégrer les path avec JavaScript. https://github.com/FriendsOfSymfony/FOSJsRoutingBundle (Je ne l'ai pas encore fait et apparemment le lien est mort =() Ce que j'ai fait en attendant, c'est de mettre l'URL en dur.

Je t'invite également à lire ce sujet ou j'était également bloqué http://www.siteduzero.com/forum-83-779 [...] -et-type.html
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 12:40:40

1/ Voila pour la requête
public function getLivreWithChapitre($id)
    {
        $queryBuilder = $this->_em->createQueryBuilder();

        $queryBuilder->select('c')
            ->from('BTProjectBundle:chapitre', 'c')
            ->where('c.livre_id = :livre')
            ->setParameter('livre', $id)
            ->orderBy('c.chapitre', 'ASC')
            ->groupBy('c.chapitre');

        return $queryBuilder->getQuery()
            ->getArrayResult();
    }

2/ merci pour la recommandation :)
4/ Oui d'après l'outil de débogage j'arrive bien dans le contrôleur, et mon JS et dans un fichier Twig donc apparemment y a pas de soucis avec le path dans ce cas-la.
Je vais regarder ça et aussi ça http://www.siteduzero.com/forum-83-770 [...] box-lies.html qui sait peut etre que je trouverais enfin la solution ^^

EDIT
Ok donc j'avais complétement oublier de créer la route :/ donc la quand je définis un chapitre le champ chapitre me retourne "undefined" et pourtant j'ai bien la réponse de ce type avec l'outil debogage
"{"chapitre":[{"id":20,"chapitre":2},{"id":51,"chapitre":3}]}"
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 14:27:51

Je pense savoir ton erreur,

<script type="text/javascript">

        $(".ChoiceLivre").change(function() {

        var vendor = $("select.ChoiceLivre option:selected").val();
        var DATA = 'id=' + vendor;

        $.ajax({
        type: "POST",
        dataType: 'json',
        url:  "{{ path('pages_c_u')}}",
        data: DATA,
        success: function(msg)
        {
        $.each(msg, function(index, chapitre)
        {
        $('.ChoiceChapitre').html('');
        $('.ChoiceChapitre').append('<option value="'+ chapitre.id +'" selected="selected"> '+ chapitre[0].name +' </option>');
        });
        }
        });
        });

    </script>


A ta ligne 18, fait plus tôt "chapitre.name" au lieu de "chapitre[0].name"
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 14:49:09

Non ça me retourne toujours 'undefined'
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 15:21:55

Je me suis trompé, normalement "chapitre[0].name" est correcte mias à quoi correspond ton "chapitre[0].name" ? Surtout le ".name" ?

Parce que tu récupère : "{"chapitre":[{"id":20,"chapitre":2},{"id":51,"chapitre":3}]}" , théoriquement tu devrais avoir :

- "chapitre[0].id" et "chapitre[0].chapitre" ? Et non ".name" =S Je peux me planter aussi ^^
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 15:30:42

:)
exact j'avais pas fais attention à .name, merci !
Juste pour savoir le 'each' juste au dessus c'est une sorte de boucle au cas ou il y aurait plusieurs chapitres, parceque la il arrive a afficher qu'un seul chapitre parmi plusieurs, peut etre faut-il faire une boucle sur le controleur alors ?
D'ailleurs comment faire pour laisser la 1ere ligne du champ vide lorsqu'on charge la page et que le 1er choix ne soit pas effectuer ?

merci beaucoup !
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 15:39:17

Ton erreur est normal :

<?php
$.each(msg, function(index, chapitre)
{
    $('.ChoiceChapitre').html('');
    $('.ChoiceChapitre').append('<option value="'+ chapitre[0].id +'" selected="selected"> '+ chapitre[0].chapitre +' </option>');
});


Le ".each" est bien une boucle, mais toi à l'intérieur, à la ligne 4 tu lui dit de tout écraser puis à la ligne 5 tu lui dit d'afficher une ligne. Au final il ne devrait t'afficher que la dernière qu'il reçoit.

Sort la ligne 4 de la boucle, et même (je pense) de ta requâte AJAX et normalement il t'affichera tout ;)


EDIT

J'ai un gros doute ... Je ne sais pas si ce que je t'ai dit résolvera ton erreur .. Je pense également à rendre ton "chapitre[0]" variable ... Test les deux et tu verras. Je pense aussi à faire ceci : "chapitre[0]['chapitre']" ... Je ne sais plus, faut que tu test
  • Partager sur Facebook
  • Partager sur Twitter
7 août 2012 à 17:08:58

Finalement c'etait une boucle qui manquait :)
for(var i =0;i < chapitres.length;i++)
        {
        $('.ChoiceChapitre').append('<option value="'+ chapitres[i].id +'"> '+ chapitres[i].chapitre +' </option>');
        }

Merci !
  • Partager sur Facebook
  • Partager sur Twitter
8 août 2012 à 9:32:20

Qu'on me corrige si je dis une bêtise, mais le "each" est déjà une boucle. Normalement si tu fait ca :

<?php
<?php
$.each(msg, function(index, chapitre)
{
    $('.ChoiceChapitre').append('<option value="'+ chapitre[index].id +'" selected="selected"> '+ chapitre[index].chapitre +' </option>');
});


Est identique à ca :

<?php
for(var i =0;i < chapitres.length;i++)
        {
        $('.ChoiceChapitre').append('<option value="'+ chapitres[i].id +'"> '+ chapitres[i].chapitre +' </option>');
        }
  • Partager sur Facebook
  • Partager sur Twitter
9 août 2012 à 11:01:14

Étonnement non :o
Par contre dans mon PageType je suis obliger de mettre les 2 formulaires sinon il me retourne une erreur du coup je sais pas comment faire pour que au début du chargement de la page le champ "Chapitre" soit vide puis qu'il se remplisse

EDIT
Merci au type Choice ;)
  • Partager sur Facebook
  • Partager sur Twitter
10 août 2012 à 12:26:33

Tomii, comment t'as fait pour déclarer qu'un seul formulaire et pas les 2 ? Symfony ne t'as pas renvoyer d'erreur ou te l'as pas afficher ?
  • Partager sur Facebook
  • Partager sur Twitter
10 août 2012 à 14:06:06

Comment ca ? J'ai du mal à te suivre ...
  • Partager sur Facebook
  • Partager sur Twitter
10 août 2012 à 14:15:21

Plus haut tu avais dit que lors de la création de formulaire tu n'en qu'un seul (alors qu'on en a besoin de 2 pour un formulaire imbriquer)

C'etait ton FormulaireType et t'as mis qu'un seul Add, (moi si je mets le 2eme avec choice et en data "****" il me refuse le flush et je dois obligatoirement utiliser un type 'entity' ce qui fait qu'il charge toutes les données (donc tout les chapitres au chargement de la page))
<?php

namespace DD\TechnoServeyBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class LoadVendorsType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('name', 'entity', array('class' => 'DD\TechnoServeyBundle\Entity\vendor', 
                                          'property' => 'name'))
        ;
    }

    public function getName()
    {
        return 'dd_technoserveybundle_loadvendorstype'; // Name of the form
    }
    
    public function getDefaultOptions(array $options)
    {
    	return array('data_class' => 'DD\TechnoServeyBundle\Entity\vendor',);
    }
}

Je sais pas si c'est clair ? ^^
  • Partager sur Facebook
  • Partager sur Twitter
10 août 2012 à 14:24:11

Oserai-je apporter mon grain d'sel ?

Apparemment, pour le JavaScript, vous vous en sortez.

-
Edité par Ymox 14 mai 2013 à 18:05:13

  • Partager sur Facebook
  • Partager sur Twitter
10 août 2012 à 14:31:18

M E R C I
(c'etait array() que je trouvais pas)
vraiment merci a vous deux ! <3
  • Partager sur Facebook
  • Partager sur Twitter