Как добавить прослушиватель событий в динамически добавляемое поле с помощью Symfony Forms

Я использую прослушиватели событий для динамического изменения формы. Я хочу добавить еще один прослушиватель событий в поле, которое было добавлено динамически. Я не уверен, как это сделать.

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('first_field','choice',array(
        'choices'=>array('1'=>'First Choice','2'=>'Second Choice')
    ));

    $builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'preSetData'));
    $builder->get('first_field')->addEventListener(FormEvents::POST_SUBMIT, array($this, 'postSubmit'));
}

public function preSetData(FormEvent $event)
{
    $form = $event->getForm();
    $form->add('second_field','choice',array(
        'choices'=>array('1'=>'First Choice','2'=>'Second Choice')
    ));
    //Some how add an event listener to this field

}

public function postSubmit(FormEvent $event)
{
    $form = $event->getForm()->getParent();
    $form->add('second_field','choice',array(
        'choices'=>array('1'=>'First Choice','2'=>'Second Choice')
    ));
    //Some how add an event listener to this field
}

Я попытался просто использовать $builder в функции buildForm, чтобы добавить прослушиватель событий в second_field, но поскольку поле не существует при первоначальном создании формы, оно выдает ошибку.

Если я попытаюсь добавить новый прослушиватель событий внутри первого прослушивателя событий, выполнив следующие действия:

$form->get('second_field')->addEventListener(...)

Затем я получаю сообщение об ошибке:

Call to undefined method Symfony\Component\Form\Form::addEventListener() 

Любые предложения будут приветствоваться.


person Chase    schedule 18.08.2014    source источник
comment
Вы пытаетесь добавить третье поле на основе второго поля?   -  person Brayden Williams    schedule 18.08.2014
comment
Да и второе поле основано на первом. Подобно Select Country ->, затем в зависимости от выбранной страны добавляются состояния полей, а доступные состояния заполняются в зависимости от страны. Затем, после выбора штата, будет добавлено поле «Город», и в него будут добавлены доступные города.   -  person Chase    schedule 18.08.2014
comment
Вы можете посмотреть CraueFormFlowBundle.   -  person keyboardSmasher    schedule 18.08.2014
comment
Неплохая идея, однако я хотел бы избежать добавления нового поставщика, если это возможно. Это всего лишь еще одна зависимость, на которую можно положиться. Однако, если я не могу заставить это работать изначально, я могу попробовать.   -  person Chase    schedule 18.08.2014
comment
@keyboardSmasher Я не уверен, почему вы рекомендуете CraueFormFlowBundle. Это для изготовления многошаговых форм. Этот вопрос касается динамического добавления полей в форму на основе базовых данных.   -  person Brayden Williams    schedule 18.08.2014
comment
@BraydenWilliams Пакет выглядит так, как будто он должен выполнить то, что я хочу. Это просто много пуха, который мне тоже не нужен.   -  person Chase    schedule 18.08.2014
comment
@Chausser, удалось ли вам вызвать прослушиватель событий POST_SUBMIT для динамически добавляемого поля? У меня похожая проблема, и я немного борюсь!   -  person Jeet    schedule 22.11.2014


Ответы (3)


Если, это на самом деле.

В FormInterface нет метода addEventListener, но он есть в FormBuilderIntreface. Если вы хотите добавить какой-либо слушатель, вы должны создать поле формы с помощью конструктора форм.

Например:

   // create builder for field
   $builder = $form->getConfig()->getFormFactory()->createNamedBuilder($name, $type, null, array(
       /** any options **/
       'auto_initialize'=>false // it's important!!!
   ));
   // now you can add listener
   $builder->addEventListener(FormEvents::POST_SUBMIT, $yourCallbackHere)

   // and only now you can add field to form  
   $form->add($builder->getForm());
person Lev Semin    schedule 19.04.2015
comment
OMG, вы спасли мой день, мою начатую работу и мою мотивацию! Большое спасибо.. ! - person Delphine; 19.07.2017

Я только что потратил половину своего рабочего дня на борьбу с этим. Я использую symfony 3.2.x, и лучшее, что мне помогло, это этот ответ.

У меня была тройная зависимость (страна, штат, регион, почтовый индекс), которую я решил внутри одного и того же FormType:

    /** @var  EntityManager $em */
private $em;

/**
 * GaraFormType constructor.
 *
 * @param EntityManager $em
 */
public function __construct(EntityManager $em)
{
    $this->em        = $em;
}


    public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('country', EntityType::class, array(
            'class'       => 'Country',
            ...more attrs
        ));

    $this->stateAjaxFieldFormListener($builder);
    $this->cityAjaxFieldFormListener($builder);
    $this->zipCodeAjaxFieldFormListener($builder);
}

Каждая из этих функций обрабатывает одно из динамических полей, и все они одинаковы:

private function stateAjaxFieldFormListener(FormBuilderInterface $builder)
{
    $localizationFormModifier = function (FormInterface $form, Country $country = null) {
        $stateInCountry = $this->em->getRepository("State")->findBy(array("country" => $country));

        if ($form->has('state') && ! $form->isSubmitted()) {
            $form->remove('state');
        }
        $form
            ->add('state', EntityType::class, array(
                'choices'     => $stateInCountry,
                'class'       => 'State',
            ));
    };
    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($localizationFormModifier) {
        /** @var ClienteTemp $data */
        $data    = $event->getData();
        $country = null !== $data ? $data->getCountry() : null;

        $localizationFormModifier($event->getForm(), $country);
    });
    $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($localizationFormModifier) {
        $data      = $event->getData();
        $countryId = array_key_exists('country', $data) ? $data['country'] : null;
        $country   = $this->em->getRepository("Country")->find($countryId);
        $localizationFormModifier($event->getForm(), $country);
    });
}

Просто измените ссылки на сущности для двух других функций: cityAjaxFieldFormListener и zipCodeAjaxFieldFormListener.

person Diego    schedule 27.07.2017

Вам действительно не нужно добавлять прослушиватель событий к first_field или second_field. Вы можете сохранить прослушиватель событий в родительской форме и проверить как отправленные, так и установленные данные, чтобы определить, включают ли они данные для first_field. Если это так, добавьте second_field. В том же прослушивателе проверьте, были ли данные установлены или отправлены в second_field. Если да, добавьте третье поле.

Аналогичная концепция описана в документации здесь: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data

person Brayden Williams    schedule 18.08.2014
comment
Я просмотрел это руководство 100 раз. Проблема в том, что вам все еще нужно подключиться к слушателю post_submit. И единственный способ сделать это в соответствии с этим руководством — напрямую прикрепить его к полю. В этом и заключается проблема, так как я не могу прикрепить прослушиватель post_submit к полю, которое было динамически добавлено другим слушателем. - person Chase; 18.08.2014
comment
Это отлично работает для события pre_set_data, потому что оно прикреплено к родительской форме, и я могу полностью проверить вложенность. Проблема возникает только с событием post_submit - person Chase; 18.08.2014
comment
Почему вы должны делать проверку в post_submit? У меня есть каскадные поля страны/штата/города в одном из моих приложений, и я проверяю pre_submit. - person Brayden Williams; 18.08.2014
comment
попробую без и дам знать - person Chase; 18.08.2014