2013-12-12 22 views
9

Tôi đang tạo ứng dụng Symfony và sử dụng các sự kiện biểu mẫu với một số jquery/ajax để thực hiện toàn bộ "trạng thái/địa phương". Tôi có một vấn đề nhỏ mặc dù, tôi đang sử dụng định dạng Tỉnh -> Thành phố -> Ngoại ô. Bây giờ như xa như tôi có thể nói với mã của tôi là tốt, nhưng khi thực hiện lượt truy cập các phần mà tôi thêm một người nghe đến "Thành phố" lựa chọn, nó ném một lỗi nói như sau:Thêm trình xử lý sự kiện để tạo thành phần tử được thêm bởi trình nghe sự kiện

The child with the name "physicalCity" does not exist.

Điều này rõ ràng xảy ra khi tôi thử và thêm trình xử lý sự kiện vào trường mới được tạo, do đó thêm trình xử lý sự kiện vào phần tử được tạo bởi trình xử lý sự kiện?

Một phần của mã bên dưới ... Tôi đang làm gì sai? Bất kỳ trợ giúp sẽ được rất nhiều đánh giá cao!

public function buildForm(FormBuilderInterface $builder, array $options) { 
     $builder 
      ->add('schoolName') 
      ->add('physicalProvince', 'entity', array(
       'mapped' => false, 
       'class' => 'MY\MainBundle\Entity\Province', 
       'empty_value' => 'Select a province', 
       'attr' => array(
        'class' => 'province', 
        'data-show' => 'physical-city', 
       ) 
      )); 

     /* 
     * For the physical cities 
     */ 
     $physicalCityModifier = function(FormInterface $form, Province $province = null) { 
      if (null !== $province) 
       $cities = $province->getCities(); 
      else 
       $cities = array(); 

      $form->add('physicalCity', 'entity', array(
       'mapped' => false, 
       'class' => 'MY\MainBundle\Entity\City', 
       'empty_value' => 'Select a province first', 
       'choices' => $cities, 
       'attr' => array(
        'class' => 'city physical-city', 
        'data-show' => 'physical-suburb' 
       ) 
      )); 
     }; 

     $builder->addEventListener(
      FormEvents::PRE_SET_DATA, 
      function(FormEvent $event) use ($physicalCityModifier) { 
       $data = $event->getData(); 
       if (is_object($data->getPhysicalSuburb())) 
        $province = $data->getPhysicalSuburb()->getCity()->getProvince(); 
       else 
        $province = null; 

       $physicalCityModifier($event->getForm(), $province); 
      } 
     ); 

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

     /* 
     * For the physical suburbs 
     */ 
     $physicalSuburbModifier = function(FormInterface $form, City $city = null) { 
      if (null !== $city) 
       $suburbs = $city->getSuburbs(); 
      else 
       $suburbs = array(); 

      $form->add('physicalSuburb', null, array(
       'choices' => $suburbs, 
       'empty_value' => 'Select a city first', 
       'attr' => array(
        'class' => 'physical-suburb' 
       ), 
      )); 
     }; 

     $builder->addEventListener(
      FormEvents::PRE_SET_DATA, 
      function(FormEvent $event) use ($physicalSuburbModifier) { 
       $data = $event->getData(); 
       if (is_object($data->getCity())) 
        $city = $data->getCity(); 
       else 
        $city = null; 

       $physicalSuburbModifier($event->getForm(), $city); 
      } 
     ); 

     $builder->get('physicalCity')->addEventListener(
      FormEvents::POST_SUBMIT, 
      function(FormEvent $event) use ($physicalSuburbModifier) { 
       $city = $event->getForm()->getData(); 

       $physicalSuburbModifier($event->getForm()->getParent(), $city); 
      } 
     ); 
} 

Trả lời

14

Nếu bất cứ ai có một vấn đề tương tự, tôi cuối cùng đã nhận nó đúng với thuê bao sự kiện cho từng lĩnh vực, với sự giúp đỡ từ this site (dịch nó cho những dân gian không nói tiếng Tây Ban Nha giữa chúng ta).

Về cơ bản, những gì tôi đã làm là tạo một lớp Người đăng ký mới cho mỗi trường, bao gồm tỉnh, và sau đó chỉ cần tạo trình tạo truy vấn bên trong mỗi trường để điền giá trị của chúng vào các trường trước đó. Các mã được hiển thị dưới đây.

AddProvinceFieldSubscriber.php

class AddProvinceFieldSubscriber implements EventSubscriberInterface { 
    private $factory; 
    private $fieldName; 
    private $type; 

    public function __construct(FormFactoryInterface $factory, $fieldName) { 
     $this->factory = $factory; 
     $this->fieldName = $fieldName . 'Province'; 
     $this->type = $fieldName; 
    } 

    public static function getSubscribedEvents() { 
     return array(
      FormEvents::PRE_SET_DATA => 'preSetData', 
      FormEvents::PRE_SUBMIT => 'preSubmit', 
     ); 
    } 

    private function addProvinceForm(FormInterface $form, $province) { 
     $form->add($this->factory->createNamed($this->fieldName, 'entity', $province, array(
      'class' => 'MyThing\MainBundle\Entity\Province', 
      'mapped' => false, 
      'empty_value' => 'Select a province', 
      'query_builder' => function (EntityRepository $repository) { 
       $qb = $repository->createQueryBuilder('p'); 
       return $qb; 
      }, 
      'auto_initialize' => false, 
      'attr' => array(
       'class' => 'province ' . $this->type .'-province', 
       'data-show' => $this->type . '-city', 
      ) 
     ))); 
    } 

    public function preSetData(FormEvent $event) { 
     $form = $event->getForm(); 
     $data = $event->getData(); 

     if (null === $data) 
      return; 

     $fieldName = 'get' . ucwords($this->type) . 'Suburb'; 
     $province = ($data->$fieldName()) ? $data->$fieldName()->getCity()->getProvince() : null; 
     $this->addProvinceForm($form, $province); 
    } 

    public function preSubmit(FormEvent $event) { 
     $form = $event->getForm(); 
     $data = $event->getData(); 

     if (null === $data) 
      return; 

     $province = array_key_exists($this->fieldName, $data) ? $data[$this->fieldName] : null; 
     $this->addProvinceForm($form, $province); 
    } 
} 

AddCityFieldSubscriber.php

class AddCityFieldSubscriber implements EventSubscriberInterface { 
    private $factory; 
    private $fieldName; 
    private $provinceName; 
    private $suburbName; 
    private $type; 

    public function __construct(FormFactoryInterface $factory, $fieldName) { 
     $this->factory = $factory; 
     $this->fieldName = $fieldName . 'City'; 
     $this->provinceName = $fieldName . 'Province'; 
     $this->suburbName = $fieldName . 'Suburb'; 
     $this->type = $fieldName; 
    } 

    public static function getSubscribedEvents() { 
     return array(
      FormEvents::PRE_SET_DATA => 'preSetData', 
      FormEvents::PRE_SUBMIT => 'preSubmit', 
     ); 
    } 

    private function addCityForm(FormInterface $form, $city, $province) { 
     $form->add($this->factory->createNamed($this->fieldName, 'entity', $city, array(
      'class' => 'MyThing\MainBundle\Entity\City', 
      'empty_value' => 'Select a city', 
      'mapped' => false, 
      'query_builder' => function (EntityRepository $repository) use ($province) { 
       $qb = $repository->createQueryBuilder('c') 
           ->innerJoin('c.province', 'province'); 
       if ($province instanceof Province) { 
        $qb->where('c.province = :province') 
         ->setParameter('province', $province); 
       } elseif (is_numeric($province)) { 
        $qb->where('province.id = :province') 
         ->setParameter('province', $province); 
       } else { 
        $qb->where('province.provinceName = :province') 
         ->setParameter('province', null); 
       } 

       return $qb; 
      }, 
      'auto_initialize' => false, 
      'attr' => array(
       'class' => 'city ' . $this->type . '-city', 
       'data-show' => $this->type . '-suburb', 
      ) 
     ))); 
    } 

    public function preSetData(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) { 
      return; 
     } 

     $fieldName = 'get' . ucwords($this->suburbName); 
     $city = ($data->$fieldName()) ? $data->$fieldName()->getCity() : null; 
     $province = ($city) ? $city->getProvince() : null; 
     $this->addCityForm($form, $city, $province); 
    } 

    public function preSubmit(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) 
      return; 

     $city = array_key_exists($this->fieldName, $data) ? $data[$this->fieldName] : null; 
     $province = array_key_exists($this->provinceName, $data) ? $data[$this->provinceName] : null; 
     $this->addCityForm($form, $city, $province); 
    } 
} 

Và cuối cùng AddSuburbFieldSubscriber.php

class AddSuburbFieldSubscriber implements EventSubscriberInterface { 
    private $factory; 
    private $fieldName; 
    private $type; 

    public function __construct(FormFactoryInterface $factory, $fieldName) { 
     $this->factory = $factory; 
     $this->fieldName = $fieldName . 'Suburb'; 
     $this->type = $fieldName; 
    } 

    public static function getSubscribedEvents() { 
     return array(
      FormEvents::PRE_SET_DATA => 'preSetData', 
      FormEvents::PRE_SUBMIT => 'preSubmit', 
     ); 
    } 

    private function addSuburbForm(FormInterface $form, $city) { 
     $form->add($this->factory->createNamed($this->fieldName, 'entity', null, array(
      'class' => 'MyThing\MainBundle\Entity\Suburb', 
      'empty_value' => 'Select a suburb', 
      'query_builder' => function (EntityRepository $repository) use ($city) { 
       $qb = $repository->createQueryBuilder('s') 
           ->innerJoin('s.city', 'city'); 

       if ($city instanceof City) { 
        $qb->where('s.city = :city') 
         ->setParameter('city', $city); 
       } elseif (is_numeric($city)) { 
        $qb->where('city.id = :city') 
         ->setParameter('city', $city); 
       } else { 
        $qb->where('city.cityName = :city') 
         ->setParameter('city', null); 
       } 
        $sql = $qb->getQuery()->getSQL(); 

       return $qb; 
      }, 
      'auto_initialize' => false, 
      'attr' => array(
       'class' => 'suburb ' . $this->type . '-suburb', 
      ), 
     ))); 
    } 

    public function preSetData(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) 
      return; 

     $fieldName = 'get' . ucwords($this->fieldName); 
     $city = ($data->$fieldName()) ? $data->$fieldName()->getCity() : null; 
     $this->addSuburbForm($form, $city); 
    } 

    public function preSubmit(FormEvent $event) { 
     $data = $event->getData(); 
     $form = $event->getForm(); 

     if (null === $data) 
      return; 

     $city = array_key_exists($this->type . 'City', $data) ? $data[$this->type . 'City'] : null; 
     $this->addSuburbForm($form, $city); 
    } 
} 

tôi đã có thêm một số công cụ bổ sung trong đó, nhưng bạn sẽ có được nắm lấy nó.

Trong loại hình thức của tôi, tôi chỉ đơn giản là bổ sung như sau:

$builder 
    ->addEventSubscriber(new AddProvinceFieldSubscriber($factory, 'postal')) 
    ->addEventSubscriber(new AddCityFieldSubscriber($factory, 'postal')) 
    ->addEventSubscriber(new AddSuburbFieldSubscriber($factory, 'postal')) 
//... 

Và hạnh phúc ngày! Hy vọng điều này sẽ giúp ai đó.

Ngoài ra, tôi đã thêm các thuộc tính data-show để đơn giản hóa quy trình AJAX của tôi, chỉ trong trường hợp ai đó đang thắc mắc.

+2

Công việc tuyệt vời! Bạn đã cứu ngày của tôi, cảm ơn bạn! :) – Gianluca78

+0

Tính năng này có hoạt động khi bạn chỉnh sửa nội dung này không. Đối với tôi thì không. Bạn cũng có thể trả lời phiên bản Symfony nào mà bạn đã làm việc này? – Jeet

+0

Có nó đã làm việc cho tôi. Đây là Sf 2.4 tôi tin, không thể nhớ chính xác. Chỉ cần thử và chơi với các trường hợp quyết định trình xây dựng truy vấn. Có lẽ một cái gì đó trong đó là lạ với trường hợp của bạn. Và cài đặt XDebug! Giúp đỡ rất nhiều. – iLikeBreakfast

Các vấn đề liên quan