简体   繁体   English

Symfony动态表单提交的表单

[英]Symfony Dynamic form Submitted Forms

I'm following the tutorial at http://symfony.com/doc/current/form/dynamic_form_modification.html#dynamic-generation-for-submitted-forms 我正在http://symfony.com/doc/current/form/dynamic_form_modification.html#dynamic-generation-for-submitted-forms上关注此教程

The idea is I got 3 class Animal => Spieces => Race During the creation of a new animal, I would like to change dynamically the choice for the Race depending of the Spieces. 我的想法是让我获得3类Animal => Spieces => Race。在创建新动物时,我想根据Spieces来动态更改Race的选择。

Here are my Classes : Race 这是我的课程:种族

class Race
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=255, unique=true)
     */
    private $nom;

    /**
     * @ORM\ManyToOne(targetEntity="Rendy\AppBundle\Entity\Espece", inversedBy="race")
     * @ORM\JoinColumn(name="espece_id", referencedColumnName="id", onDelete="CASCADE", nullable=false)
     */
    private $espece;

Class Animal 类动物

class Animal
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="Nom", type="string", length=30)
     */
    private $nom;

    /**
     * @var Espece
     *
     *
     * @ORM\ManyToOne(targetEntity="Espece")
     * @ORM\JoinColumn(name="espece_id", referencedColumnName="id", onDelete="CASCADE")
     */
    private $espece;

    /**
     * @var string
     *
     * @ORM\ManyToOne(targetEntity="Race")
     * @ORM\JoinColumn(name="race_id", referencedColumnName="id", onDelete="CASCADE")
     */
    private $race;

And class Spieces : 和Spieces类:

class Espece
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=255, unique=true)
     */
    private $nom;


    /**
     * @ORM\OneToMany(targetEntity="Race", mappedBy="espece")
     * @ORM\JoinColumn(name="race_id", referencedColumnName="id")
     */
    private $race;

   /**
     * Get race
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getRace()
    {
        return $this->race;
    }

Here is my Controller 这是我的控制器

public function newAction(Request $request)
    {
        $animal = new Animal();

        $form = $this->createForm(AnimalType::class, $animal);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
          // do something after
                      }

        return $this->render('RendyAppBundle:animal:new.html.twig', array(
            'form' => $form->createView(),
        ));
    }

Here my AnimalType Form 这是我的AnimalType表格

class AnimalType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('nom');


        $builder->add('espece', EntityType::class, array(
            'class'         => 'RendyAppBundle:Espece',
            'choice_label'  => 'nom',
            'placeholder'   => '',
            ));

        $formModifier = function (FormInterface $form, Espece $espece = null) {
            $race = null === $espece ? array() : $espece->getRace();

            $form->add('race', EntityType::class, array(
                'class'         => 'RendyAppBundle:Race',
                'choice_label'  => 'nom',
                'placeholder'   => '',
                'choices'       => $race,
            ));
        };
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {

                $data = $event->getData();
                $formModifier($event->getForm(), $data->getEspece());
            }
        );

        $builder->get('espece')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
                $espece = $event->getForm()->getData();
                $formModifier($event->getForm()->getParent(), $espece);
            }
        );

End the view ! 结束视图!

{% block body%}

    {{ form_start(form) }}
        {# render the task's only field: description #}
        {{ form_row(form.nom) }}
        {{ form_row(form.espece, {'id': 'test','attr': {'onChange': 'changed()'}}) }}
        {{ form_row(form.race, {'id': 'animal_race', 'attr': { 'class': 'form-control'}}) }}
        {{ form_row(form.sexe) }}
        {{ form_row(form.age) }}

        {{ form_row(form.puce) }}
        {{ form_row(form.poids) }}

        <h3>Comportement</h3>
        <ul class="comportement">
            {# iterate over each existing tag and render its only field: name #}
            {% for comportement in form.comportement %}
                <li>{{ form_row(comportement.name) }}</li>
            {% endfor %}
        </ul>
    {{ form_end(form) }}



{% endblock %}

{% block ajax %}
<script>

function changed() {
    var espece = $('#test');
    // ... retrieve the corresponding form.
    var $form = $('#form');

    console.log($form);
    // Simulate form data, but only include the selected sport value.
    var data = {};
    data[espece.attr('nom')] = espece.val();
    // Submit data via AJAX to the form's action path.
    jQuery.ajax({
        url : $form.attr('action'),
        type: "POST",
        data: data,
        success: function (html) {
            console.log(html)
            $("#animal_race").replaceWith(
                // ... with the returned one from the AJAX response.
                $(html).find("#animal_race")
            );
            // Position field now displays the appropriate positions.
        }
    });
}
</script>
{% endblock %}

The Ajax function is called when I change the value of "Especes" but my field Race is still blank... (my block ajax is after the block javascripts) 当我更改“ Especes”的值但我的字段Race仍然为空时,将调用Ajax函数(我的块ajax在块javascript之后)

The Ajax request : POST Parameters Key Value undefined "2" Ajax请求:POST参数键值未定义“ 2”

For information when I do a simple Animal->getEspece()->getRace(); 有关当我执行简单的Animal-> getEspece()-> getRace();时的信息; I got an Array with the good information. 我得到了一个包含良好信息的数组。

I googled, try, googled try and I think I miss something. 我用谷歌搜索,尝试,用谷歌搜索,我想我错过了一些东西。

Thank you for your help 谢谢您的帮助

You are sending the post-request (in the AJAX call) to the same URL (the form-action url) as the page is loaded from (the newAction's Request). 您正在将请求后的请求(在AJAX调用中)发送到与页面加载时相同的URL(表单操作URL)(newAction的Request)。 This could work if your newAction method would actually be sending data to incoming POST/GET requests, but this is not at all the case here. 如果您的newAction方法实际上是将数据发送到传入的POST / GET请求中,那么这可能会起作用,但是在此情况并非如此。

I recommend to always create a separate route (and thus separate controller method) specifically for the POST request. 我建议始终为POST请求创建一个单独的路由(从而创建一个单独的控制器方法)。 You also cannot send the data (that is in an object when you retrieve it from the database) 'as is'. 您也不能“按原样”发送数据(从数据库中检索数据时在对象中)。 You are gonna have to convert it into for example, JSON. 您将不得不将其转换为例如JSON。 You could potentially convert your whole object directly to JSON ( https://symfony.com/doc/current/components/serializer.html ), but it might be better to only get the information that you need. 您可以将整个对象直接转换为JSON( https://symfony.com/doc/current/components/serializer.html ),但是最好只获取所需的信息。 For this you can create an array that holds this information 为此,您可以创建一个保存此信息的数组

All in all, your controller method would look something like this: 总而言之,您的控制器方法将如下所示:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

public function getRacesJsonAction(Request $request)
{
    //Get the race data here that you want to send (edit to your own needs)
    $race = $Animal->getEspece()->getRace();

    //Convert the entity directly to a JSON
    $jsonContent = $serializer->serialize($race, 'json');

    //create a response 
    $response = new Response($jsonContent);
    $response->headers->set('Content-Type', 'application/json');

    return $response;
}

In your frontend you are gonna have to decode the json into a javascript array like so: 在您的前端中,您将必须将json解码为如下所示的javascript数组:

  $.ajax({
      type: 'POST',
      url: url,
      data: {
          data: dataObj
      },
      dataType: 'json',
      success: function(data) {
        console.log('success');
        //Obj is the array with information now
        obj = JSON.parse(json);
      },
      error: function(data) {
        console.log('fail');
      }
  });

However you cannot directly fill this information that is in the obj-array. 但是,您不能直接填写obj数组中的此信息。 You are gonna have to parse it, since every entry in an HTML-dropdown is wrapped like this: 您将不得不对其进行解析,因为HTML下拉列表中的每个条目都是这样包装的:

<ul>
</li>race1</li>
</li>race2</li>
</li>race3</li>
</ul>

Its a extensive implementation. 它的广泛实施。 I might have made errors in the syntax, so beware. 我可能在语法上犯了错误,所以要当心。 I also recommend you to use 'FOSJsRoutingBundle', it enables you to create url's from routes in javascript. 我还建议您使用“ FOSJsRoutingBundle”,它使您能够从javascript中的路由创建url。 Something you would likely use to convert the route's path into a javascript variable that holds the url. 您可能会使用某些东西将路线的路径转换为包含url的javascript变量。

Good luck! 祝好运!

Here is my code who is working 这是我的代码正在工作

Controller : 控制器:

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

use AppBundle\Entity\Animal;
use AppBundle\Form\Type\AnimalType;
// ...

class MeetupController extends Controller
{
    /**
     * @Route("/animal")
     */
    public function animalAction(Request $request)
    {
        $meetup = new Animal();
        $form = $this->createForm(AnimalType::class, $meetup);
        $form->handleRequest($request);
        if ($form->isValid()) {
            // ... save the meetup, redirect etc.
        }

        return $this->render(
            ':Meetup:animal.html.twig',
            array('form' => $form->createView())
        );
    }

    // ...
}

animal.html.twig animal.html.twig

{% block body %}
{{ form_start(form) }}

   {{ form_row(form.espece) }}
   {{ form_row(form.race) }}
    {# ... #}
{{ form_end(form) }}

<script   src="https://code.jquery.com/jquery-2.2.4.min.js"   integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="   crossorigin="anonymous"></script>
<script>
    var $espece = $('#animal_espece');
    // When especegets selected ...
    $espece.change(function() {
        console.log("Dans la fonction Change");
        // ... retrieve the corresponding form.
        var $form = $(this).closest('form');
        // Simulate form data, but only include the selected espece value.
        var data = {};
        data[$espece.attr('name')] = $espece.val();

        // Submit data via AJAX to the form's action path.
        $.ajax({
            url : $form.attr('action'),
            type: $form.attr('method'),
            data : data,
            success: function(html) {
                // Replace current race field ...
                $('#animal_race').replaceWith(
                        // ... with the returned one from the AJAX response.
                        $(html).find('#animal_race')
                );
                // race field now displays the appropriate positions.
            }
        });
    });
</script>
{% endblock %}

AnimalType AnimalType

<?php

namespace AppBundle\Form\Type;

use AppBundle\Entity\Espece;
use AppBundle\Entity\Animal;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormInterface;

// ...

class AnimalType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('espece', EntityType::class, array(
                'class'       => 'AppBundle:Espece',
                'placeholder' => '',
            ))
        ;

        $formModifier = function (FormInterface $form, Espece $sport = null) {
            $positions = null === $sport ? array() : $sport->getAvailablePositions();

            $form->add('race', EntityType::class, array(
                'class'       => 'AppBundle:Race',
                'placeholder' => '',
                'choices'     => $positions,
            ));
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {
                // this would be your entity, i.e. SportMeetup
                $data = $event->getData();

                $formModifier($event->getForm(), $data->getEspece());
            }
        );

        $builder->get('espece')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifier) {
                $sport = $event->getForm()->getData();
                $formModifier($event->getForm()->getParent(), $sport);
            }
        );
    }

}

Espece Entity 特殊实体

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

/**
 * Espece
 *
 * @ORM\Table(name="espece")
* @ORM\Entity(repositoryClass="AppBundle\Repository\EspeceRepository")
 */
class Espece
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=255, unique=true)
     */
    private $nom;

   /**
    * @var Collection|Race[]
    *
    * @ORM\OneToMany(targetEntity="Race", mappedBy="espece")
    */
   protected $racesdisponibles;


    public function __constructor()
    {
        $this->racesdisponibles = new ArrayCollection();
    }

    public function __toString()
    {
        return $this->nom;
    }

And Race Entity 和种族实体

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Race
 *
 * @ORM\Table(name="race")
  * @ORM\Entity(repositoryClass="AppBundle\Repository\RaceRepository")
 */
class Race
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=255, unique=true)
     */
    private $nom;

    /**
     * @var Espece
     * @ORM\ManyToOne(targetEntity="Espece", inversedBy="racesdisponibles")
     * @ORM\JoinColumn(name="espece_id", referencedColumnName="id", onDelete="CASCADE", nullable=false)
     */
    private $espece;

    public function __toString()
    {
        return $this->nom;
    }

If needed send me a message and I will send you the Bundle :) My mistake was here 如果需要,请给我发消息,然后我会向您发送捆绑包:)我的错误在这里

data[espece.attr('nom')] = espece.val();

Regarding the DOM the good anwser is 关于DOM,好的答案是

data[espece.attr('name')] = espece.val();

I thought that "name" was an attribute to sport entity and no to the <div name="beeeeer"> 我认为“名称”是体育实体的属性,而不是<div name="beeeeer">

Hope that will help someone 希望能对某人有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM