Reputation: 1370
I am trying to set the choices for a form select dynamically since the choices come from a service call. However, when the form renders in the view, the choices are not there.
I'm doing the following in the FormType
<?php
namespace My\Form\Customer;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ItemReturnRequestForm extends AbstractType
{
/**
* @var EventSubscriberInterface
*/
protected $reasonsSubscriber;
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName()
{
return 'item_return_request';
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('reason', 'choice', [
'label' => 'order.returns.reason_for_return',
'required' => true,
'multiple' => false,
'expanded' => false,
'placeholder' => 'order.returns.reasons.empty',
'empty_data' => null,
]);
$builder->addEventSubscriber($this->reasonsSubscriber);
}
/**
* @param EventSubscriberInterface $reasonsSubscriber
*/
public function setReasonsSubscriber(EventSubscriberInterface $reasonsSubscriber)
{
$this->reasonsSubscriber = $reasonsSubscriber;
}
}
The FormType
has a service definition which injects the EventSubscriber
instance since that is also a service definition with it's own dependencies.
The EventSubscrbier
looks like
<?php
namespace My\Form\EventSubscriber;
use My\Customer\ItemReturnAware;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class ReturnReasonEventSubscriber implements EventSubscriberInterface
{
use ItemReturnAware;
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SET_DATA => 'getReturnReasons',
];
}
public function getReturnReasons(FormEvent $event)
{
$form = $event->getForm();
if ($form->has('reason')) {
$options = $form->get('reason')->getConfig()->getOptions();
$options['choices'] = $this->itemReturnService->getReasons();
$form->add('reason', 'choice', $options);
}
}
}
Everything seems to work fine up until this point. Using XDEBUG I can see that the EventSubscriber
is being triggered. The service call sets $option['choices']
to the expected array value & the field is added successfully.
However, when the form gets rendered. it's as if the EventSubscriber
had never been called.
If it makes a difference, the options array is an un-ordered numeric list.
i.e.
$options = [
10 => 'First choice',
15 => 'Second choice',
20 => 'Third choice',
];
Any ideas?
Upvotes: 4
Views: 3670
Reputation: 601
This is an ancient question, but today I found it on the top results searching for event listener to modify form choices.
In my context I have an entity programmatically created, and I redirect the user to the editAction to finish filling the fields. I have one choice that I can apply only in this particular case, I don't want to allow my user to use it outside it.
That's why I user the POST_SET_DATA event, because I already have an entity with populated fields.
This event listener is set in the formType, inside the
public function buildForm(FormBuilderInterface $builder, array $options)
{
Here a working solution for symfony 3.4:
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
// get the form from the event
$form = $event->getForm();
if ('myParticularMode' == $form->get('mode')->getData()) {
// get the field options
$options = $form->get('mode')->getConfig()->getOptions();
// add the mode to the choices array
$options['choices']['MY_PARTICULAR_MODE'] = 'myParticularMode_display_name';
$form->add('mode', ChoiceType::class, $options);
}
});
If you want to replace the choices, you can remove this:
$options = $form->get('mode')->getConfig()->getOptions();
and set a new array for choices.
Upvotes: 2