2015-02-23 28 views
0

我正尝试创建搜索表单。在这个表格中,我有两个选择框,一个用于国家,另一个用于名为“目的地”的城市。第二个取决于选定的国家。我也有其他一些投入。提交表单后无法恢复一个数据

选择国家后,使用ajax查询正确显示与其相关的所有城市。

问题是如果我选择一个国家并提交表单,目的地不会在地址栏中恢复,但如果我不选择国家/地区,目的地将会恢复。

这是我听不懂没有选择国家

/q?title=&country=&destination=&airport=&departureDate=&returnDate=&price= 

地址栏的显示,这是,如果我选择一个国家的地址栏的显示方式。正如你所看到的目标是缺少

/q?title=&country=1&airport=&departureDate=&returnDate=&price= 

注意我使用的是类似的形式与POST方法来创建或编辑新的旅行和正常工作

SearchTravelType

namespace AppBundle\Form; 

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

//........ 
use Symfony\Component\Form\FormInterface; 
use AppBundle\Entity\Country; 

class SearchTravelType extends AbstractType 
{ 
public function buildForm(FormBuilderInterface $builder, array $options) 
{ 

    ->add('country', 'entity', array(
    'required' => true, 
    'class' => 'AppBundle:Country', 
    'property' => 'en', 
    'multiple' => false, 
    'expanded' => false, 
    'label' => 'ِCountry', 
    'empty_value' => '')) 
    //.... 

    $formModifier = function (FormInterface $form, Country $country = null) { 
     $cities = null === $country ? array() : $country->getCities(); 

     $form->add('destination', 'entity', array(
      'class'  => 'AppBundle:CityWorld', 
      'choices'  => $cities, 
      'multiple' => false, 
      'expanded' => false, 
      'property' => 'name', 
      'label' => 'Destination')); 
    }; 

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

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

    $builder->get('country')->addEventListener(
     FormEvents::POST_SUBMIT, 
     function (FormEvent $event) use ($formModifier) { 
      // 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! 
      $formModifier($event->getForm()->getParent(), $country); 
     } 
    ); 


} 

public function setDefaultOptions(OptionsResolverInterface $resolver) 
{ 
    $resolver->setDefaults(array(
     'data_class' => 'AppBundle\Entity\Travel' 
    )); 
} 

public function getName() 
{ 
    return null; 
} 
} 

这是表单和JavaScript代码

<form method="get" action="" class="form-horizontal" role="form" > 

{{ form_widget(form.country, { 'id': 'country' }) }} 

{{ form_widget(form.destination, { 'id': 'city' }) }} 

//............. 
</form> 

<script type="text/javascript"> 
var $county = $('#country'); 

$county.change(function() { 
    // ... retrieve the corresponding form. 
    var $form = $(this).closest('form'); 

    var data = {}; 
    data[$county.attr('name')] = $county.val(); 
    // Submit data via AJAX to the form's action path. 
    $.ajax({ 
     url: '{{ path('dashboard_travel_search', {'agence_slug': agence.slug}) }}', 
      type: 'POST',   data: data, 
     success: function (html) { 
      $('#city').replaceWith(
        // ... with the returned one from the AJAX response. 
        $(html).find('#city') 
      ); 
     } 
    }); 
}); 

这是控制器

/** 
* @ParamConverter("agence", options={"mapping": {"agence_slug":"slug"}}) 
*/ 
public function searchAction(Request $request, Agence $agence) 
{ 
    if (false === $this->get('security.context')->isGranted('view', $agence)) { 
     throw new AccessDeniedException('Unauthorised access!'); 
    } 
    /* Instantiate Travel to not get this error 
    Error: Call to a member function getCountry() on a non-object 
    */ 
    $travel = new Travel(); 

    $form = $this->createForm(new SearchTravelType(), $travel); 
    if ($request->getMethod() == 'POST') { 
     $form->handleRequest($request); 
    } 

    $em = $this->getDoctrine()->getManager(); 
    $paginator = $this->get('knp_paginator'); 

    $title = $request->query->get('title'); 
    $country = $request->query->get('country'); 
    $destination = $request->query->get('destination'); 
    $price = $request->query->get('price'); 
    $departureDate = $request->query->get('departureDate'); 
    $returnDate = $request->query->get('returnDate'); 
    $nbDays = $request->query->get('nbDays'); 
    $nbNights = $request->query->get('nbNights'); 
    $airport = $request->query->get('airport'); 
    $enabled = $request->query->get('enabled'); 

    $qb = $em->getRepository('AppBundle:Travel')->getListSearchTravelsDashboard($agence, $title, $country, $destination, $price, $departureDate, $returnDate, $nbDays, $nbNights, $airport, $enabled); 

    $pagination = $paginator->paginate(
     $qb, 
     $request->query->get('page', 1), 10); 
    $pagination->setSortableTemplate('KnpPaginatorBundle:Pagination:sortable_link_dashboard.html.twig'); 

    return $this->render('AppBundle:Dashboard/Travel:list-search.html.twig', array(
     'pagination' => $pagination, 
     'form' => $form->createView(), 
     'agence' => $agence, 
    )); 

} 

这是生成的表单的嫩枝HTML标记:

<table id="sample-table-1" class="table table-responsives table-striped table-hover"> 
    <tr> 
     <form class="form-inline" role="form" method="get" action=""> 
      <td class="center">-</td> 
      <td>{{ form_widget(form.title) }}</td> 
      <td>{{ form_widget(form.country, { 'id': 'country' }) }}</td> 
      <td>{{ form_widget(form.destination, { 'id': 'city' }) }}</td> 
      <td>{{ form_widget(form.airport) }}</td> 
      <td>{{ form_widget(form.departureDate) }}</td> 
      <td>{{ form_widget(form.returnDate) }}</td> 
      <td>{{ form_widget(form.price) }}</td> 
      <td>{{ form_widget(form.nbDays) }}</td> 
      <td>{{ form_widget(form.nbNights) }}</td> 
      <td>{{ form_widget(form.enabled) }} {{ form_rest(form) }}</td> 
      <td><span class="input-group-btn"> 
      <button type="submit" class="btn btn-purple btn-sm" title="Rechercher"> 
       <i class="icon-search bigger-110"></i></button> 
      </span> 
     </form> 
    </tr> 

我已经把它在表外,现在工作得很好。有什么解释吗?

+0

您是否在使用AJAX显示相关城市?如果是这样,请提供用于显示相关城市的JavaScript。在选择城市之后,请检查您是否可以使用JavaScript接收选定的选项。如果您无法通过JavaScript接收选中的选择选项,请检查在DOM中选择城市后脚本将发生的变化。它可以是,它只会改变一个类或属性来显示选择内容,但是它不会检查选项(例如使用'checked'属性)。 – dude 2015-02-23 22:36:53

+0

@julmot,我使用Ajax JavaScript根据国家/地区字段中的当前选择更新目的地表单字段,并使用EVENTS选择城市。以下是文档中的示例。 (http://symfony.com/doc/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data) – hous 2015-02-24 10:28:24

回答

0

问题是因为表单到表这样

<table id="sample-table-1" class="table table-responsives table-striped table-hover"> 
    <tr> 
      <form class="form-inline" role="form" method="get" action=""> 
       <td class="center">-</td> 
       <td>{{ form_widget(form.title) }}</td> 
       <td>{{ form_widget(form.country, { 'id': 'country' }) }}</td> 
       <td>{{ form_widget(form.destination, { 'id': 'city' }) }}</td> 
       <td>{{ form_widget(form.airport) }}</td> 
       <td>{{ form_widget(form.departureDate) }}</td> 
       <td>{{ form_widget(form.returnDate) }}</td> 
       <td>{{ form_widget(form.price) }}</td> 
       <td>{{ form_widget(form.nbDays) }}</td> 
       <td>{{ form_widget(form.nbNights) }}</td> 
       <td>{{ form_widget(form.enabled) }} {{ form_rest(form) }}</td> 
       <td><span class="input-group-btn"> 
       <button type="submit" class="btn btn-purple btn-sm" title="Rechercher"> 
        <i class="icon-search bigger-110"></i></button> 
       </span> 
      </form> 
     </tr> 

我已经把它外,现在工作得很好。有没有解释?

0

首先,更好地使用单独的控制器操作来检索您需要的城市,并仅替换选择字段中的选项。用分页等渲染整个表单有点矫枉过正。 其次,检查你从ajax调用得到的html究竟是什么,尤其是$(html).find('#city')选择的输入是否包含'name'属性。从提交的表单中缺少的值与Symfony2框架本身没有什么共同之处,都是关于正确的HTML内容。

1

它不起作用,因为您不能在trHTML元素中使用formHTML元素。根据W3C规范,tr元素只能包含tdth元素 - 请参阅permitted contents of the tr element in HTML5

这是一个与W3C标准部分中提到的问题类似的问题 - 标记已损坏。见unexpected table markup informations in the W3C HTML standards

而且,并不是只有你有form直接在tr元素中的元素,但你也不要你的提交按钮,我想,有什么做的问题,也是后关闭最后td标签。

您的标记是所有问题的来源,我不知道任何浏览器是否可以正确处理此类代码。通过W3C验证器验证所有内容,然后您可以在控制器等中搜索问题。无效的HTML代码可能是许多意想不到的问题的根源,而这些问题很难调试,并且您通常最终会在错误的地方搜索。我在这里讲述了经验。

+0

@hous我已经添加了您的答案的原始问题的Twig示例代码,我认为它也应该存在,以便于参考(由于正在进行StackOverflow同行评审过程,编辑可能不会显示)。 – XanatosLightfiren 2015-02-24 20:19:32

+0

但为什么除非“目的地”,所有其他输入都会被重新采集?你不觉得它与JavaScript代码有关系吗? '成功:功能(HTML){ $('#城市)replaceWith( $(HTML).find('#城市) );' – hous 2015-02-25 13:12:06

+0

@hous它可能是这样,但只。因为HTML无效。可能#city字段没有被找到(在响应中),所以它可能被替换为空值。有效的HTML代码是开始寻找其他问题最重要的 - 然后您可能会开始调试您的JS代码。你自己写道,当你纠正HTML结构时,一切都开始按预期工作 - 所以也许这两件事情实际上是相连的,但这一切都归结为HTML首先是无效的,在我看来。 – XanatosLightfiren 2015-02-28 13:56:09