级联多选的Symfony2表单的最佳方式



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

namespace ********BundleEntity;
use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;
class Country
{
  private $id;
  private $name;
  /**
   * @var integer $regions
   * 
   * @ORMOneToMany(targetEntity="Region", mappedBy="Country")
   */
  protected $regions;
  //...
}
class Region
{
  private $id;
  private $name;
  /**
   * @var integer $country
   *
   * @AssertType(type="*******BundleEntityCountry")
   * @ORMManyToOne(targetEntity="Country", inversedBy="regions")
   * @ORMJoinColumn(name="country_id", referencedColumnName="id", nullable=false)
   */
  private $country;
  /**
   * @ORMOneToMany(targetEntity="City", mappedBy="Region")
   */
  protected $cities;
}
class City
{
    private $id;
    private $name;
    /**
     * @var integer $region
     *
     * @AssertType(type="********BundleEntityRegion")
     * @ORMManyToOne(targetEntity="Region", inversedBy="cities")
     * @ORMJoinColumn(name="region_id", referencedColumnName="id", nullable=false)
     */
    private $region;
    /**
     * @ORMOneToMany(targetEntity="Company", mappedBy="City")
     */
    protected $companys;
//...
}

这是我的城市课程:

namespace ********BundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
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' => '********BundleEntityCity',
    ));
  }
  public function getName()
  {
    return 'city';
  }
}

这就形成了一个基本的HTML5表单,其中有一个用于名称的textBox和一个所有区域都可用的SelectBox。

我的问题是,添加第一个SelectBox的最佳方式是什么,它可以让我选择国家,以过滤第二个SelectBox并减少地区选择的数量?

EventListener?事件调度程序组件?

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

在这里查找一些想法

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

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

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

第二种方法对表单的初始加载有更大的负担,因为所有国家及其相关地区都必须加载(从数据库或文本文件或存储它们的任何地方),并以JS可以轻松读取的格式呈现。

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

我自己在表单上做这件事。我更改了一个字段(一个产品),可以测量数量的单位也会更新。我正在使用一个带有参数的宏来更容易地调整它。

宏:

{% 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调用。

我希望这能有所帮助。

正如Carlos Granados所说,您必须使用客户端编程:Javascript。我也遇到了和你相同的问题,并提出了一个非常适合我的解决方案,这是代码笔上的片段,你可以从(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-------------------------//

相关内容

  • 没有找到相关文章

最新更新