2

I want to create a dependend select box: if the first selectbox is selected, the second selectbox should be filled.

My first selectbox isn't mapped to the model. I set the value manually in my controller with $form->get('emailTemplateBlockType')->setData($emailTemplateBlockType) .. How can I use this data in my form event to create my second selectbox?

    $builder
        ->add('emailTemplateBlockType', 'entity', array(
            'class' => 'MbDbMVibesBundle:EmailTemplateBlockType',
            'property' => 'name',
            'mapped' => false,
            'empty_value' => 'Choose a block type',
            'attr' => array(
                'class' => 'emailTemplateBlockTypeSelect',
            )
        ))
        ->add('save', 'submit');


    $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
        $form = $event->getForm();
        $data = $event->getData();

            echo "name: ".$form->get('emailTemplateBlockType')->getData()->getName();
            die;
    });

I have an onChange event with jQuery that posts the choice of the first selectbox to my frontcontroller again. The front controller then creates the form again, but this time with the value of the first selectbox added. But since it's not a submit, I think using the POST_SUBMIT event will not work either.

Snippet from my controller:

    $form = $this->createForm(new EmailTemplateSiteEmailTemplateBlockType(), $entity, array(
        'action' => $this->generateUrl('_email_tpl_site_block_edit', array(
            'emailTemplateSiteId' => $emailTemplateSiteId,
            'emailTemplateSiteBlockId' => $emailTemplateSiteBlockId,
        ))
    ));

    if ($request->request->get('blockTypeId')) {
        $this->get('logger')->debug('setting block type');

        $emailTemplateBlockType = $em->getRepository('MbDbMVibesBundle:EmailTemplateBlockType')
            ->find($request->request->get('blockTypeId'));

        if ($emailTemplateBlockType)
            $form->get('emailTemplateBlockType')->setData($emailTemplateBlockType);
        else
            throw new $this->createNotFoundException('Cannot find blocktype with id '.$request->request->get('blockTypeId'));

    }

    $form->handleRequest($request);
3
  • Have you tried binding that event to POST_SUBMIT instead? Nov 7, 2014 at 15:32
  • Yes, I just tried.. doesn't work because I don't submit to reload the form. Maybe I should edit my question.
    – rolandow
    Nov 7, 2014 at 19:37
  • 1
    @rolandow: use PRE_SUBMIT event, u get raw data.
    – jamek
    Nov 10, 2014 at 18:45

2 Answers 2

2

I think I finally nailed it. I'll describe my pitfalls here, for a full article on how I eventually implemented this see Forms in Symfony2: dependent selectboxes

First of all, it seems I have to submit the full form in order to trigger the form event PRE_SUBMIT. I couldn't just post one variable to the form.

Second, I totally missed that inside the PRE_SUBMIT event, the data is stored in an array instead of an object, which was actually perfectly mentioned in this post. So I should have used:

$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($addEmailTemplateBlock) {
    $form = $event->getForm();
    $data = $event->getData();

    if (array_key_exists('emailTemplateBlockType', $data)) {
        $addEmailTemplateBlock($form, $data['emailTemplateBlockType']);
    }
});

Third is that my unmapped form element can't be accessed in PRE_SET_DATA, but it can in POST_SET_DATA.

Fourth is that I was having issues when I would change the first selectbox, if I had already selected the first and second. This would make sense, because the value in the second selectbox would indeed be invalid, if the first selectbox would change. The easiest way to solve this was to just set the value to empty in the change event of the first selectbox.

I would also like to point out that this approach doesn't require any additional scripting in the controller or javascript when you add more dependent fields. All logic for this is done inside the form builder, so I think it creates better reusable code than the approach of Airam.

0

I've wrote this small static method:

public static function getUnmappedData($form): array
{
    $fields = array_filter($form->all(), function($field)
    {
        $config = $field->getConfig();
        $options = $config->getOptions();
        $zval = (true == $options['mapped']);
        return($zval);
    });

    $zval = array_map(function($field)
    {
        $zval = $field->getData();
        
        return($zval);
    }, $fields);

    return($zval);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.