Json 如何使用Symfony表单动态填充下拉列表?

Json 如何使用Symfony表单动态填充下拉列表?,json,forms,symfony,Json,Forms,Symfony,我想动态填写我的表格(见图) 状态select(html标记)由javascript函数用json文件填充: function onChangeCountries(countries, states) { $(countries).on("change", function(ev) { var countryId = $(this).val(); if (countryId != '') { states.empty();

我想动态填写我的表格(见图)

状态
select
(html标记)由javascript函数用json文件填充:

function onChangeCountries(countries, states) {
    $(countries).on("change", function(ev) {
        var countryId = $(this).val();

        if (countryId != '') {

            states.empty();
            states.append('<option selected="true" disabled>Choose state</option>');
            states.prop('selectedIndex', 0);

            $.getJSON(statesUrl, function (data) {
                $.each(data['states'], function (key, entry) {
                    if (entry.country_id == countryId) {
                        states.append($('<option></option>').attr('value', entry.id).text(entry.name));
                    }
                })
            });
        }
    });
}
这里的问题是,我无法根据用户输入填写选项。 我还收到一个OutOfMemoryException(cities.json中有40000多个城市)

编辑

在dlondero回答之后,我还没有解决我的问题,这是我新的
LocationType
类:

<?php

// src/Form/LocationType.php
namespace App\Form;

use App\Entity\Location;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class LocationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $countries = json_decode(file_get_contents("js/countries.json"), TRUE)['countries'];
        $countriesChoices = array();

        foreach($countries as $country) {
            $countriesChoices[$country['name']] = $country['id'];
        }

        $builder
            ->add('zip_code', TextType::class)
            ->add('street', TextType::class)
            ->add('country', ChoiceType::class, array(
                'choices'  => $countriesChoices
            ))
            ->add('area', ChoiceType::class, array(
                'choices'  => array()
            ))
            ->add('city', ChoiceType::class, array(
                'choices'  => array()
            ))
        ;

        $formModifierStates = function (FormInterface $form, $countryId = null) {
            $statesChoices = array();

            if (null !== $countryId) {
                $states = json_decode(file_get_contents("js/states.json"), TRUE)['states'];

                foreach($states as $state) {
                    if ($countryId == $state['country_id']) {
                        $statesChoices[$state['name']] = $state['id'];
                    }
                }
            }

            $form->add('area', ChoiceType::class, array(
                'choices'  => $statesChoices
            ));
        };

        $formModifierCities = function (FormInterface $form, $stateId = null) {
            $citiesChoices = array();

            if (null !== $stateId) {
                $cities = json_decode(file_get_contents("js/cities.json"), TRUE)['cities'];

                foreach($cities as $city) {
                    if ($stateId == $city['state_id']) {
                        $citiesChoices[$city['name']] = $city['id'];
                    }
                }
            }

            $form->add('city', ChoiceType::class, array(
                'choices'  => $citiesChoices
            ));
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifierStates) {
                $data = $event->getData(); // country id

                $formModifierStates($event->getForm(), $data);
            }
        );

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifierCities) {
                $data = $event->getData(); // state id

                $formModifierCities($event->getForm(), $data);
            }
        );

        $builder->get('country')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifierStates) {
                // It's important here to fetch $event->getForm()->getData(), as
                // $event->getData() will get you the client data (that is, the ID)
                $country = $event->getForm()->getData();

                // since we've added the listener to the child, we'll have to pass on
                // the parent to the callback functions!
                $formModifierStates($event->getForm()->getParent(), $country);
            }
        );

        $builder->get('area')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifierCities) {
                // It's important here to fetch $event->getForm()->getData(), as
                // $event->getData() will get you the client data (that is, the ID)
                $state = $event->getForm()->getData();

                // since we've added the listener to the child, we'll have to pass on
                // the parent to the callback functions!
                $formModifierCities($event->getForm()->getParent(), $state);
            }
        );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Location::class,
        ));
    }
}

您需要根据为上一次选择所做的选择动态加载它们。这种方法与使用JS的方法非常相似


您可以在官方文档中看到一个示例:。

谢谢dlondero,我会看看这个。您添加了AJAX调用吗?检查上面链接的最后一个代码部分。为了获取数据和填充后续选择,需要添加一些绑定onchange事件的JS。是的,我添加了Ajax调用,当选择一个州时,它填充city
select
,但我认为,我出现了提到的错误,原因是,
LocationType
buildForm
依赖字段应仅添加在事件侦听器中,而不是最初添加到生成器中。
<?php

// src/Form/LocationType.php
namespace App\Form;

use App\Entity\Location;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class LocationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $countries = json_decode(file_get_contents("js/countries.json"), TRUE)['countries'];
        $countriesChoices = array();

        foreach($countries as $country) {
            $countriesChoices[$country['name']] = $country['id'];
        }

        $builder
            ->add('zip_code', TextType::class)
            ->add('street', TextType::class)
            ->add('country', ChoiceType::class, array(
                'choices'  => $countriesChoices
            ))
            ->add('area', ChoiceType::class, array(
                'choices'  => array()
            ))
            ->add('city', ChoiceType::class, array(
                'choices'  => array()
            ))
        ;

        $formModifierStates = function (FormInterface $form, $countryId = null) {
            $statesChoices = array();

            if (null !== $countryId) {
                $states = json_decode(file_get_contents("js/states.json"), TRUE)['states'];

                foreach($states as $state) {
                    if ($countryId == $state['country_id']) {
                        $statesChoices[$state['name']] = $state['id'];
                    }
                }
            }

            $form->add('area', ChoiceType::class, array(
                'choices'  => $statesChoices
            ));
        };

        $formModifierCities = function (FormInterface $form, $stateId = null) {
            $citiesChoices = array();

            if (null !== $stateId) {
                $cities = json_decode(file_get_contents("js/cities.json"), TRUE)['cities'];

                foreach($cities as $city) {
                    if ($stateId == $city['state_id']) {
                        $citiesChoices[$city['name']] = $city['id'];
                    }
                }
            }

            $form->add('city', ChoiceType::class, array(
                'choices'  => $citiesChoices
            ));
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifierStates) {
                $data = $event->getData(); // country id

                $formModifierStates($event->getForm(), $data);
            }
        );

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifierCities) {
                $data = $event->getData(); // state id

                $formModifierCities($event->getForm(), $data);
            }
        );

        $builder->get('country')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifierStates) {
                // It's important here to fetch $event->getForm()->getData(), as
                // $event->getData() will get you the client data (that is, the ID)
                $country = $event->getForm()->getData();

                // since we've added the listener to the child, we'll have to pass on
                // the parent to the callback functions!
                $formModifierStates($event->getForm()->getParent(), $country);
            }
        );

        $builder->get('area')->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) use ($formModifierCities) {
                // It's important here to fetch $event->getForm()->getData(), as
                // $event->getData() will get you the client data (that is, the ID)
                $state = $event->getForm()->getData();

                // since we've added the listener to the child, we'll have to pass on
                // the parent to the callback functions!
                $formModifierCities($event->getForm()->getParent(), $state);
            }
        );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Location::class,
        ));
    }
}