Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Symfony3] ajouter un champ au builder

    22 septembre 2017 à 3:55:22

    Bonjour, 


    Pour faire simple, je suis entrain de coder un mini calculateur qui prend en charge  4 champs de base pour un jeux vidéos. 

    Voila une image donc actuellement elle marche il n'y a pas de soucis, cependant j'aimerai que si l'utilisateur choisis une autre valeur que 1 dans la liste déroulante (nmb Tacleur), le premier champ soit dupliquer  pour ajouter un nouveau tacle (pour 2 personnages donc). 

    En cherchant un peu j'ai trouver un code JS qui fonctionne mais que  je n'arrive pas a implémenter dans symfony3, surtout pour récupérer les champs.

    document.querySelector('#add').addEventListener('click', function(event) {
       
      var first = document.querySelector('div p');
      first.parentNode.appendChild(first.cloneNode(true));
       
    });


    Mon formulaire : 

    <?php
    
    namespace Dofus\CalculateurBundle\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    
    class PlayerType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('tacle',TextType::class)
                ->add('fuite',TextType::class)
                ->add('pa',TextType::class)
                ->add('pm',TextType::class)
                ->add('nmbTacleur', ChoiceType::class, array(
                    'choices' => array(
                        1 => "1",
                        2 => "2", 
                        3 => "3",
                        4 => "4")));
        }
        
        /**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'Dofus\CalculateurBundle\Entity\Player'
            ));
        }
    
        /**
         * {@inheritdoc}
         */
        public function getBlockPrefix()
        {
            return 'dofus_calculateurbundle_player';
        }
    
    
    }
    




    Mon code du controller : 

    $em = $this->getDoctrine()->getManager();
                $player = new Player();
                $form   = $this->get('form.factory')->create(PlayerType::class, $player);
    
                if ($request->isMethod('POST')
                && $form->handleRequest($request)->isValid()
                && $form->isSubmitted()) {
                    $data = $form->getData();
                    $resPourcentage = ($data->getFuite()+2)/((2 * ($data->getTacle()+2)));
                    $paPerdu = $data->getPa()-(round($data->getPa() * $resPourcentage));
                    $pmPerdu = $data->getPm()-(round($data->getPm() * $resPourcentage));
                    if($paPerdu == 0 && $pmPerdu == 0) {
                        $request->getSession()->getFlashBag()->add('notice', 'Vous êtes libre de vos mouvements, vous n\'êtes pas taclé(e)');
                    } else {
                        $request->getSession()->getFlashBag()->add('notice', 'Pour vous detaclez, vous allez perdre : '.$paPerdu.' PA et '.$pmPerdu.' PM');
                    }
                }
    
                return $this->render('DofusCalculateurBundle:Player:fuite.html.twig', array(
                    'form' => $form->createView())
                    );



    et ma vue  :

    {% block body %}
      {% for message in app.session.flashbag.get('notice') %}
        <div class="alert alert-info">{{ message }}</div>
      {% endfor %}
      <div class="formulaire-fuite">
        <p class="title-formulaire-fuite">Calculateur de détaclage</p>
        {{ form_start(form, {'attr': {'class': 'form-horizontal'}}) }}
        {{ form_rest(form) }}
        <button type="submit" class="btnFuite" name="fuite"> Calculer </button>
        {{ form_end(form) }}
        {# Fermeture de la balise <form> du formulaire HTML #}
      </div>
        <br>
    {% endblock %}

    Donc pour résumer, je souhaiterai que si dans la liste déroulante on choisis 2 alors un nouveau champ Tacle apparait (au total donc 2) et que je puisse récupèrer les 2 bien distinctement pour faire les calculs dans mon controleur.
    Si quelqu'un pouvais m'aider merci :) 


    -
    Edité par Anthony63 22 septembre 2017 à 4:00:10

    • Partager sur Facebook
    • Partager sur Twitter
      22 septembre 2017 à 4:19:49

      Bonjour,

      Suggestion de solution : utiliser les événements pour faire un formulaire dynamique. https://symfony.com/doc/current/form/dynamic_form_modification.html

      A+

      • Partager sur Facebook
      • Partager sur Twitter
        22 septembre 2017 à 11:30:37

        monkey3d a écrit:

        Bonjour,

        Suggestion de solution : utiliser les événements pour faire un formulaire dynamique. https://symfony.com/doc/current/form/dynamic_form_modification.html

        A+


        Merci bien cependant je ne trouve pas un cas similaire au mien car je n'ai pas besoin d'utilliser la bdd ou alors ce n'est pas lors d'une insertion d'un objet, je vais relire et rechercher je pense.....

        SI quelqu'un pourrais me donner un début de code svp, je suis débutant en symfony dsl

        -
        Edité par Anthony63 22 septembre 2017 à 12:14:24

        • Partager sur Facebook
        • Partager sur Twitter
          22 septembre 2017 à 13:09:06

          Il y a un exemple dans la doc Symfony qui me semble en partie correspondre au besoin exprimé : quand il est choisit une certaine valeur dans un champ alors le formulaire se reconfigure ... il me semble que c'est ce que tu veux faire.

          Par ailleurs si je comprend le besoin, quand il est choisi une autre valeur que 1 il faut faire une nouveau formulaire avec les 4 champs de base.  C'est aussi expliqué dans la doc du tuto https://openclassrooms.com/courses/developpez-votre-site-web-avec-le-framework-symfony2/creer-des-formulaires-avec-symfony2

          avec le paragraphe : imbriquer un même formulaire plusieurs fois.

          Dans ces tutos, tu as des codes complets : maintenant faut les travailler par rapport à ton besoin.

          A+

          • Partager sur Facebook
          • Partager sur Twitter
            22 septembre 2017 à 13:18:21

            monkey3d a écrit:

            Il y a un exemple dans la doc Symfony qui me semble en partie correspondre au besoin exprimé : quand il est choisit une certaine valeur dans un champ alors le formulaire se reconfigure ... il me semble que c'est ce que tu veux faire.

            Par ailleurs si je comprend le besoin, quand il est choisi une autre valeur que 1 il faut faire une nouveau formulaire avec les 4 champs de base.  C'est aussi expliqué dans la doc du tuto https://openclassrooms.com/courses/developpez-votre-site-web-avec-le-framework-symfony2/creer-des-formulaires-avec-symfony2

            avec le paragraphe : imbriquer un même formulaire plusieurs fois.

            Dans ces tutos, tu as des codes complets : maintenant faut les travailler par rapport à ton besoin.

            A+



            C'est pas tout à fait ça car dans la doc c'est  par rapport aux informations d'un objet, moi c'est juste des données que je veux récupérer pour faire  un calcul puis je ne les utiliserait plus, les formulaire imbriqués j'ai bien compris mais moi je veux qu'il n'y est que le premier champ (Tacle) qui soit dupliquer et plusieurs fois à la suite. 
            Exemple je choisis  2 dans la liste deroulante : 

            j'aurai donc 2 champs tacle puis 1 champ fuite, 1 champ PA et 1 champ PM

            Je choisis 4 dans la liste deroulante : 

            j'aurai donc 4 champs tacle puis 1 champ fuite, 1 champ PA et 1 champ PM



            Je dois donc forcément créer un formulaire avec uniquement le champ tacle que  je devrais insérer lorsque la valeur de la liste déroulante et supérieur à 1 ? Dois-je le faire en event listener ou JS/AJAX ?  et je rappel que je n'ai nul besoin de persister ces informations, aucune relation entre les entités, c'est uniquement pour faire de simple calcul coté controller, pas besoin de collection etc...

            -
            Edité par Anthony63 22 septembre 2017 à 13:33:16

            • Partager sur Facebook
            • Partager sur Twitter
              22 septembre 2017 à 21:00:44

              Je me permet de faire un up,


              J'ai suivis la doc en modifiant toute  la structure donc je vous montre le code :

              Les 2 entités : 

              <?php
              
              namespace Dofus\CalculateurBundle\Entity;
              
              use Doctrine\ORM\Mapping as ORM;
              
              /**
               * Player
               *
               * @ORM\Table(name="player")
               * @ORM\Entity(repositoryClass="Dofus\CalculateurBundle\Repository\PlayerRepository")
               */
              class Player
              {
                  /**
                   * @var int
                   *
                   * @ORM\Column(name="id", type="integer")
                   * @ORM\Id
                   * @ORM\GeneratedValue(strategy="AUTO")
                   */
                  private $id;
              
                  /**
                   * @var int
                   *
                   * @ORM\Column(name="fuite", type="integer")
                   */
                  private $fuite;
              
                  /**
                   * @var int
                   *
                   * @ORM\Column(name="pa", type="integer")
                   */
                  private $pa;
              
                  /**
                   * @var int
                   *
                   * @ORM\Column(name="pm", type="integer")
                   */
                  private $pm;
              
                  /**
                   * @ORM\ManyToMany(targetEntity="Dofus\CalculateurBundle\Entity\Tacle", cascade={"persist"})
                   * @ORM\JoinTable(name="dofus_player_tacle")
                   */
                  private $tacleurs;
              
                  /**
                   * Get id
                   *
                   * @return int
                   */
                  public function getId()
                  {
                      return $this->id;
                  }
              
                  /**
                   * Set fuite
                   *
                   * @param integer $fuite
                   *
                   * @return Player
                   */
                  public function setFuite($fuite)
                  {
                      $this->fuite = $fuite;
              
                      return $this;
                  }
              
                  /**
                   * Get fuite
                   *
                   * @return int
                   */
                  public function getFuite()
                  {
                      return $this->fuite;
                  }
              
                  /**
                   * Set pa
                   *
                   * @param integer $pa
                   *
                   * @return Player
                   */
                  public function setPa($pa)
                  {
                      $this->pa = $pa;
              
                      return $this;
                  }
              
                  /**
                   * Get pa
                   *
                   * @return int
                   */
                  public function getPa()
                  {
                      return $this->pa;
                  }
              
                  /**
                   * Set pm
                   *
                   * @param integer $pm
                   *
                   * @return Player
                   */
                  public function setPm($pm)
                  {
                      $this->pm = $pm;
              
                      return $this;
                  }
              
                  /**
                   * Get pm
                   *
                   * @return int
                   */
                  public function getPm()
                  {
                      return $this->pm;
                  }
                  /**
                   * Constructor
                   */
                  public function __construct()
                  {
                      $this->tacleurs = new \Doctrine\Common\Collections\ArrayCollection();
                  }
              
                  /**
                   * Add tacleur
                   *
                   * @param \Dofus\CalculateurBundle\Entity\Tacle $tacleur
                   *
                   * @return Player
                   */
                  public function addTacleur(\Dofus\CalculateurBundle\Entity\Tacle $tacleur)
                  {
                      $this->tacleurs[] = $tacleur;
              
                      return $this;
                  }
              
                  /**
                   * Remove tacleur
                   *
                   * @param \Dofus\CalculateurBundle\Entity\Tacle $tacleur
                   */
                  public function removeTacleur(\Dofus\CalculateurBundle\Entity\Tacle $tacleur)
                  {
                      $this->tacleurs->removeElement($tacleur);
                  }
              
                  /**
                   * Get tacleurs
                   *
                   * @return \Doctrine\Common\Collections\Collection
                   */
                  public function getTacleurs()
                  {
                      return $this->tacleurs;
                  }
              }
              
              <?php
              
              namespace Dofus\CalculateurBundle\Entity;
              
              use Doctrine\ORM\Mapping as ORM;
              
              /**
               * Tacle
               *
               * @ORM\Table(name="tacle")
               * @ORM\Entity(repositoryClass="Dofus\CalculateurBundle\Repository\TacleRepository")
               */
              class Tacle
              {
                  /**
                   * @var int
                   *
                   * @ORM\Column(name="id", type="integer")
                   * @ORM\Id
                   * @ORM\GeneratedValue(strategy="AUTO")
                   */
                  private $id;
              
                  /**
                   * @var int
                   *
                   * @ORM\Column(name="nmbTacle", type="integer")
                   */
                  private $nmbTacle;
              
              
                  /**
                   * Get id
                   *
                   * @return int
                   */
                  public function getId()
                  {
                      return $this->id;
                  }
              
                  /**
                   * Set nmbTacle
                   *
                   * @param integer $nmbTacle
                   *
                   * @return Tacle
                   */
                  public function setNmbTacle($nmbTacle)
                  {
                      $this->nmbTacle = $nmbTacle;
              
                      return $this;
                  }
              
                  /**
                   * Get nmbTacle
                   *
                   * @return int
                   */
                  public function getNmbTacle()
                  {
                      return $this->nmbTacle;
                  }
              }
              
              

              mes 2 formType : 

              <?php
              
              namespace Dofus\CalculateurBundle\Form;
              
              use Symfony\Component\Form\AbstractType;
              use Symfony\Component\Form\FormBuilderInterface;
              use Symfony\Component\OptionsResolver\OptionsResolver;
              use Symfony\Component\Form\Extension\Core\Type\TextType;
              
              
              class TacleType extends AbstractType
              {
                  /**
                   * {@inheritdoc}
                   */
                  public function buildForm(FormBuilderInterface $builder, array $options)
                  {
                      $builder->add('nmbTacle', TextType::class);
                  }
                  
                  /**
                   * {@inheritdoc}
                   */
                  public function configureOptions(OptionsResolver $resolver)
                  {
                      $resolver->setDefaults(array(
                          'data_class' => 'Dofus\CalculateurBundle\Entity\Tacle'
                      ));
                  }
              
                  /**
                   * {@inheritdoc}
                   */
                  public function getBlockPrefix()
                  {
                      return 'dofus_calculateurbundle_tacle';
                  }
              
              
              }
              
              <?php
              
              namespace Dofus\CalculateurBundle\Form;
              
              use Symfony\Component\Form\AbstractType;
              use Symfony\Component\Form\FormBuilderInterface;
              use Symfony\Component\Form\Extension\Core\Type\TextType;
              use Symfony\Component\Form\Extension\Core\Type\CollectionType;
              use Symfony\Component\Form\Extension\Core\Type\SubmitType;
              use Symfony\Component\OptionsResolver\OptionsResolver;
              
              class PlayerType extends AbstractType
              {
                  /**
                   * {@inheritdoc}
                   */
                  public function buildForm(FormBuilderInterface $builder, array $options)
                  {
                      $builder
                              ->add('fuite',TextType::class)
                              ->add('pa',TextType::class)
                              ->add('pm',TextType::class)
                              ->add('tacleurs',CollectionType::class,array(
                                  'entry_type' => TacleType::class,
                                  'allow_add' => true,
                                  'allow_delete' => true
                                  ))
                              ->add('save', SubmitType::class);
                  }
                  
                  /**
                   * {@inheritdoc}
                   */
                  public function configureOptions(OptionsResolver $resolver)
                  {
                      $resolver->setDefaults(array(
                          'data_class' => 'Dofus\CalculateurBundle\Entity\Player'
                      ));
                  }
              
                  /**
                   * {@inheritdoc}
                   */
                  public function getBlockPrefix()
                  {
                      return 'dofus_calculateurbundle_player';
                  }
              
              
              }
              




              et pour finir ma  vue

              {# Le formulaire reste inchangé #}
              <div class="well">
                {{ form(form) }}
              </div>
              
              {# On charge la bibliothèque jQuery. Ici, je la prends depuis le CDN google
                 mais si vous l'avez en local, changez simplement l'adresse. #}
              <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
              
              {# Voici le script en question : #}
              <script type="text/javascript">
                $(document).ready(function() {
                  // On récupère la balise <div> en question qui contient l'attribut « data-prototype » qui nous intéresse.
                  var $container = $('div#dofus_calculateurbundle_player_tacle');
              
                  // On ajoute un lien pour ajouter une nouvelle catégorie
                  var $addLink = $('<a href="#" id="add_tacle" class="btn btn-default">Ajouter un Tacleur</a>');
                  $container.append($addLink);
              
                  // On ajoute un nouveau champ à chaque clic sur le lien d'ajout.
                  $addLink.click(function(e) {
                    addTacleur($container);
                    e.preventDefault(); // évite qu'un # apparaisse dans l'URL
                    return false;
                  });
              
                  // On définit un compteur unique pour nommer les champs qu'on va ajouter dynamiquement
                  var index = $container.find(':input').length;
              
                  // On ajoute un premier champ automatiquement s'il n'en existe pas déjà un (cas d'une nouvelle annonce par exemple).
                  if (index == 0) {
                    addTacleur($container);
                  } else {
                    // Pour chaque tacleur déjà existant, on ajoute un lien de suppression
                    $container.children('div').each(function() {
                      addDeleteLink($(this));
                    });
                  }
              
                  // La fonction qui ajoute un formulaire Tacle
                  function addTacleur($container) {
                    var $prototype = $($container.attr('data-prototype').replace(/__name__label__/g, 'Tacleur n°' + (index+1))
                        .replace(/__name__/g, index));
              
                    // On ajoute au prototype un lien pour pouvoir supprimer le tacleur
                    addDeleteLink($prototype);
              
                    // On ajoute le prototype modifié à la fin de la balise <div>
                    $container.append($prototype);
              
                    // Enfin, on incrémente le compteur pour que le prochain ajout se fasse avec un autre numéro
                    index++;
                  }
              
                  // La fonction qui ajoute un lien de suppression d'une catégorie
                  function addDeleteLink($prototype) {
                    // Création du lien
                    $deleteLink = $('<a href="#" class="btn btn-danger">Supprimer</a>');
              
                    // Ajout du lien
                    $prototype.append($deleteLink);
              
                    // Ajout du listener sur le clic du lien
                    $deleteLink.click(function(e) {
                      $prototype.remove();
                      e.preventDefault(); // évite qu'un # apparaisse dans l'URL
                      return false;
                    });
                  }
                });
              </script>
              

               et voici l'affichage de ma vue du coup 

              J'ai pas le bouton qui permet d'ajouter un tacleur je comprend pas trop c'est sensiblement le même code a part les  entités





              • Partager sur Facebook
              • Partager sur Twitter
                23 septembre 2017 à 5:37:49

                La source de ton jquery est erronée : il faut ajouter https://ajax......................................

                c'est donc :

                https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js

                Mais là tu utilises une très vieille version de jquery : la version en cours est la 3.2.1 et là tu utilises la 1.11.1

                Si tu veux utiliser la version courante c'est :

                https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js

                As tu vérifié que l'id de ta div qui permet de générer le bouton est correct ? avec les outils de debug de ton navigateur. Je pense que non car alors tu aurais vu que le jquery n'est certainement pas chargé : cf explication ci-dessus.

                A+

                -
                Edité par monkey3d 23 septembre 2017 à 5:52:51

                • Partager sur Facebook
                • Partager sur Twitter
                  23 septembre 2017 à 6:13:21

                  monkey3d a écrit:

                  La source de ton jquery est erronée : il faut ajouter https://ajax......................................

                  c'est donc :

                  https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js

                  Mais là tu utilises une très vieille version de jquery : la version en cours est la 3.2.1 et là tu utilises la 1.11.1

                  Si tu veux utiliser la version courante c'est :

                  https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js

                  As tu vérifié que l'id de ta div qui permet de générer le bouton est correct ? avec les outils de debug de ton navigateur. Je pense que non car alors tu aurais vu que le jquery n'est certainement pas chargé : cf explication ci-dessus.

                  A+

                  -
                  Edité par monkey3d il y a 20 minutes


                  Alors en effet ct bien la div mais maintenant je peut supprimer les champs du coup ca vas pas x) j'ai tester de mettre le nom de mon attribut dans mon entité mais ca marche pas... en vrai ca me saoule jsuis sur c'est pour un truc de merde xD bref un screen :



                  <div id="dofus_calculateurbundle_player_tacleurs" data-prototype="&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;control-label required&quot;&gt;__name__label__&lt;/label&gt;&lt;div id=&quot;dofus_calculateurbundle_player_tacleurs___name__&quot;&gt;&lt;div class=&quot;form-group&quot;&gt;&lt;label class=&quot;control-label required&quot; for=&quot;dofus_calculateurbundle_player_tacleurs___name___nmbTacle&quot;&gt;Nmb tacle&lt;/label&gt;&lt;input type=&quot;text&quot; id=&quot;dofus_calculateurbundle_player_tacleurs___name___nmbTacle&quot; name=&quot;dofus_calculateurbundle_player[tacleurs][__name__][nmbTacle]&quot; required=&quot;required&quot; class=&quot;form-control&quot; /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;"></div></div><div class="form-group"><button type="submit" id="dofus_calculateurbundle_player_save" name="dofus_calculateurbundle_player[save]" class="btn-default btn">Save</button></div><input type="hidden" id="dofus_calculateurbundle_player__token" name="dofus_calculateurbundle_player[_token]" value="DL62bzGYf59GBgOIbAqPsU-QW5v1E0NnKtfsFBl3bVU" /></div></form>
                  </div>


                  J'ai essayer en mettant tacleurs mais marche pas nn plus

                  voila voila.... En tous cas merci bcp de ton aide



                  -
                  Edité par Anthony63 23 septembre 2017 à 6:22:05

                  • Partager sur Facebook
                  • Partager sur Twitter
                    23 septembre 2017 à 12:30:54

                    Alors on respire un grand coup ... ;)

                    Pour ne pas avoir le bouton supprimer, c'est simple il suffit de mettre en commentaire ou d'enlever la partie de code javascript qui génère le bouton soit :

                    // On ajoute au prototype un lien pour pouvoir supprimer le tacleur
                          //addDeleteLink($prototype);

                    Pourquoi tu n'as plus de champs Tacleurs dans ton Form ? tu l'avais au début tu as donc du modifier ton form ...

                    A+

                    • Partager sur Facebook
                    • Partager sur Twitter
                      23 septembre 2017 à 14:46:04

                      Je sais pas pk je l'ai plus x) 

                      PlayerType (si je met le use TacleType ca plante)


                      use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\OptionsResolver\OptionsResolver;
                      public function buildForm(FormBuilderInterface $builder, array $options)
                          {
                              $builder
                                      ->add('fuite',TextType::class)
                                      ->add('pa',TextType::class)
                                      ->add('pm',TextType::class)
                                      ->add('tacleurs',CollectionType::class,array(
                                          'entry_type' => TacleType::class,
                                          'allow_add' => true,
                                          'allow_delete' => true
                                          ))
                                      ->add('save', SubmitType::class);
                          }

                      et TacleType :

                      public function buildForm(FormBuilderInterface $builder, array $options)
                          {
                              $builder->add('nmbTacle', TextType::class);
                          }

                      C'est la collection qui bloque, jveux juste un champ nmbTacle




                      -
                      Edité par Anthony63 23 septembre 2017 à 15:00:05

                      • Partager sur Facebook
                      • Partager sur Twitter

                      [Symfony3] ajouter un champ au builder

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown