1

我有 3 个实体(国家、地区、城市)

namespace ****\****Bundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

class Country
{
  private $id;

  private $name;

  /**
   * @var integer $regions
   * 
   * @ORM\OneToMany(targetEntity="Region", mappedBy="Country")
   */
  protected $regions;
  //...
}

class Region
{
  private $id;

  private $name;

  /**
   * @var integer $country
   *
   * @Assert\Type(type="****\***Bundle\Entity\Country")
   * @ORM\ManyToOne(targetEntity="Country", inversedBy="regions")
   * @ORM\JoinColumn(name="country_id", referencedColumnName="id", nullable=false)
   */
  private $country;

  /**
   * @ORM\OneToMany(targetEntity="City", mappedBy="Region")
   */
  protected $cities;
}

class City
{
    private $id;

    private $name;

    /**
     * @var integer $region
     *
     * @Assert\Type(type="****\****Bundle\Entity\Region")
     * @ORM\ManyToOne(targetEntity="Region", inversedBy="cities")
     * @ORM\JoinColumn(name="region_id", referencedColumnName="id", nullable=false)
     */
    private $region;

    /**
     * @ORM\OneToMany(targetEntity="Company", mappedBy="City")
     */
    protected $companys;
//...
}

这是我的城市表格类:

namespace ****\****Bundle\Form;

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

class CityType extends AbstractType
{

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

  public function setDefaultOptions(OptionsResolverInterface $resolver)
  {
    $resolver->setDefaults(array(
        'data_class' => '****\****Bundle\Entity\City',
    ));
  }

  public function getName()
  {
    return 'city';
  }
}

这将创建一个基本的 HTML5 表单,其中包含名称的文本框和所有区域都可用的选择框。

我的问题是添加第一个 SelectBox 的最佳方法是什么,这将允许我选择国家以过滤第二个 SelectBox 并减少区域选择的数量?

事件监听器?事件调度程序组件 ?

4

4 回答 4

2

不,EventListener 和 Event dispatcher 用于发生在服务器上的事件,而不是在客户端发生的事件。您需要使用 Javascript。当其中一个选择框发生变化时,这应该触发一个 javascript 函数并进行 AJAX 调用并用该调用的结果填充另一个选择框,或者使用一些 javascript 代码来选择要在第二个框中显示的选项。

在这里寻找一些想法

于 2012-09-14T10:50:38.110 回答
1

正如 Carlos Granados 所说,您基本上有两种选择:

  1. 创建一个单独的 Symfony 操作,将国家作为参数并以 XML 或 JSON 格式返回相关区域的列表。(您可以使用Symfony\Component\HttpFoundation\JsonResponse发送 JSON 响应,但是没有对应的XmlResponse类)。每当用户更改当前选定的项目时,使用jQuery(或任何其他 JS 库甚至纯 Javascript)向服务器发送请求。在回调中(当您在 Javascript 中检索响应时),您可以更新区域选择框。您可能会发现jQuery Ajax的文档很有趣。

  2. 您将所有国家及其相关区域的列表存储在 HTML 代码中(您可以使用 JSON 或生成本机 Javascript 数组),每当用户更改国家选择框的值时,您只需替换区域选择框。

第二种方法在表单的初始加载时负载较重,因为必须加载所有国家及其相关区域(从数据库或文本文件或您存储它们的任何位置)并以 JS 可以轻松读取的格式呈现.

然而,第一种方法必须在用户每次选择另一个国家时发送一个请求。此外,您必须执行另一个操作。

于 2012-09-14T11:01:24.737 回答
0

我自己在表格上做这个。我更改了字段(产品),并且可以测量数量的单位被更新。我正在使用带有参数的宏来更轻松地调整它。

宏:

{% macro javascript_filter_unit(event, selector) %}
<script>
    $(function(){
        $('#usersection')
                .on('{{ event }}', '{{ selector }}', function(e){
                    e.preventDefault();
                    if (!$(this).val()) return;
                    $.ajax({
                        $parent: $(this).closest('.child_collection'),
                        url: $(this).attr('data-url'),
                        type: "get",
                        dataType: "json",
                        data: {'id' : $(this).val(), 'repo': $(this).attr('data-repo'), parameter: $(this).attr('data-parameter')},
                        success: function (result) {
                            if (result['success'])
                            {
                                var units = result['units'];
                                this.$parent.find('.unit').eq(0).html(units);   
                            }
                        }
                    });
                })
    });

</script>

{% endmacro %}

ajax 返回一个数组:array('success' => $value, 'units' => $html)。您使用 $html 代码并将其放在您要更改的选择位置。当然,需要修改 ajax 调用的 javascript 代码以匹配您的字段。

您可以像通常那样调用宏:

{% import ':Model/Macros:_macros.html.twig' as macros %}
{{ macros.javascript_filter_unit('change', '.unitTrigger') }}

所以我有两个论点:事件,往往是一个选择的变化。和一个选择器,它的变化会触发 ajax 调用。

我希望这会有所帮助。

于 2015-01-16T21:19:48.667 回答
0

正如 Carlos Granados 所说,您必须使用客户端编程:Javascript。我也遇到了与您相同的问题,并提出了一个对我来说非常有效的解决方案,这是codepen 上的片段,您可以从 (Cascade Ajax Selects) 中获得灵感

    //-------------------------------SELECT CASCADING-------------------------//
    var currentCities=[];
// This is a demo API key that can only be used for a short period of time, and will be unavailable soon. You should rather request your API key (free)  from http://battuta.medunes.net/   
var BATTUTA_KEY="00000000000000000000000000000000"
    // Populate country select box from battuta API
    url="http://battuta.medunes.net/api/country/all/?key="+BATTUTA_KEY+"&callback=?";
    $.getJSON(url,function(countries)
    {
        console.log(countries);
      $('#country').material_select();
        //loop through countries..
        $.each(countries,function(key,country)
        {
            $("<option></option>")
                            .attr("value",country.code)
                            .append(country.name)
                            .appendTo($("#country"));

        }); 
        // trigger "change" to fire the #state section update process
        $("#country").material_select('update');
        $("#country").trigger("change");


    });

    $("#country").on("change",function()
    {

        countryCode=$("#country").val();

        // Populate country select box from battuta API
        url="http://battuta.medunes.net/api/region/"
        +countryCode
        +"/all/?key="+BATTUTA_KEY+"&callback=?";

        $.getJSON(url,function(regions)
        {
            $("#region option").remove();
            //loop through regions..
            $.each(regions,function(key,region)
            {
                $("<option></option>")
                                .attr("value",region.region)
                                .append(region.region)
                                .appendTo($("#region"));
            });
            // trigger "change" to fire the #state section update process
            $("#region").material_select('update');
            $("#region").trigger("change");

        }); 

    });
    $("#region").on("change",function()
    {

        // Populate country select box from battuta API
        countryCode=$("#country").val();
        region=$("#region").val();
        url="http://battuta.medunes.net/api/city/"
        +countryCode
        +"/search/?region="
        +region
        +"&key="
        +BATTUTA_KEY
        +"&callback=?";

        $.getJSON(url,function(cities)
        {
            currentCities=cities;
            var i=0;
            $("#city option").remove();

            //loop through regions..
            $.each(cities,function(key,city)
            {
                $("<option></option>")
                                .attr("value",i++)
                                .append(city.city)
                        .appendTo($("#city"));
            });
            // trigger "change" to fire the #state section update process
            $("#city").material_select('update');
            $("#city").trigger("change");

        }); 

    }); 
    $("#city").on("change",function()
    {
      currentIndex=$("#city").val();
      currentCity=currentCities[currentIndex];
      city=currentCity.city;
      region=currentCity.region;
      country=currentCity.country;
      lat=currentCity.latitude;
      lng=currentCity.longitude;
      $("#location").html('<i class="fa fa-map-marker"></i> <strong> '+city+"/"+region+"</strong>("+lat+","+lng+")");
    });
   //-------------------------------END OF SELECT CASCADING-------------------------//
于 2017-07-13T21:40:52.697 回答