Symfony2 Data transformer on a Choice field type

5.5k views Asked by At

I am going step by step with the How to use Data Transformers

The problem is that what if I want to do this with a Choice type? Which I dynamically populate with jQuery?

I tested the example they provide (without creating a custom type..) and it works 100% with the text field type, but as soon as I change it to choice and give it empty choices it doesn't work, does this have to do with me populating the choices with jQuery after the page is loaded?

Example

Model [Select with the Model entity loaded with the query builder and Entity field type...]

Number [Empty choice at first, when the Model changes I make an AJAX request for the Numbers of that Model]

If I leave the Number as a text field and I manually type a valid number (looking at the database) it works, but if I leave it to jQuery and a Choice type it returns a form error with an invalid value for the Model.

In both cases I'm doing print_r($request->request) before handling the form and in both cases it submits Number => 1 which is correct in this example, but somehow it's not transforming the data when its type is Choice but when its Text it does.

This is how jQuery is populating the data for the Number select box:

<option value=”1”>1234ABCDEFG</option>

Btw, I'm transforming with the Id, which would be the value of the option selected.

1

There are 1 answers

8
Cerad On BEST ANSWER

Ok. What you need to do is to listen to the preSubmit form event and then basically accept the submitted value by adding it to your choice element.

http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data

=======================================================

I didn't look at your paste bin but here is an example that seems to work for me. It's a simple gender choice list to which I add another option client side. The preSubmit listener simply replaces the default gender choice options with an option containing whatever was submitted. You should be able to add in data transform stuff and be good to go.

namespace Cerad\Bundle\TournBundle\Form\Type\Test;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormFactoryInterface;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class DynamicFormType extends AbstractType
{
    public function getName() { return 'cerad_tourn_test_dynamic'; }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('gender', 'choice', array(
            'choices'   => array('m' => 'Male', 'f' => 'Female'),
            'required'  => false,
        ));
        $builder->addEventSubscriber(new DynamicFormListener($builder->getFormFactory()));
    }
}
class DynamicFormListener implements EventSubscriberInterface
{
    private $factory;

    public function __construct(FormFactoryInterface $factory)
    {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents()
    {
        return array(
            FormEvents::PRE_SUBMIT   => 'preSubmit',
            FormEvents::PRE_SET_DATA => 'preSetData',
        );
    }
    public function preSetData(FormEvent $event)
    {
        // Don't need
        return;
    }
    public function preSubmit(FormEvent $event)
    {
        $data = $event->getData();
        $gender = $data['gender'];
        if (!$gender) return; // If nothing was actually chosen

        $form = $event->getForm();

        /* =================================================
         * All we need to do is to replace the choice with one containing the $gender value
         * Once this is done $form->isValid() will pass
         *
         * I did attempt to just add the option to the existing gender choice 
         * but could not see how to do it.  
         * $genderForm = form->get('gender'); // Returns a Form object
         * $genderForm->addNewOptionToChoicesList ???
         * 
         * Might want to look up 'whatever' but that only comes into play
         * if the form fails validation and you paas it back to the user
         * You could also use client side javascript to replace 'whatever' with the correct value
         */
        $form->add($this->factory->createNamed('gender','choice', null, array(
            'choices'   => array($gender => 'whatever'),
            'required'  => false,
            'auto_initialize' => false,
        )));
        return;
    }
}