Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid Symfony forcing form fields display

Tags:

forms

symfony

I have a form type, setting 10 fields. In my twig template, I display 8 fields everytime, and 2 fields inside a condition :

{% if computed is not empty %}
    <div class="container-filters">
        <div class="form-group">
             {{ form_row(form.filterStart) }}
        </div>
        <div class="form-group">
              {{ form_row(form.filterEnd) }}
        </div>
        <input type="submit" name="submit" class="btn btn-evo" value="OK" />
    </div>
{% endif %}

But no matter if my condition is true or false, Symfony will display those 2 fields. If my condition is true, they will be displayed because of my {{ form_row() }} statement, which is normal behavior. If my condition is false, they will be displayed anyway, because Symfony 2 force form fields to be displayed.

How can I prevent this weird behavior ?

like image 887
VaN Avatar asked Aug 20 '14 07:08

VaN


2 Answers

I guess you have a form_end or form_rest somewhere after your presented code.

You can tell to not render remaining fields in the form_end helper :

{# don't render unrendered fields #}
{{ form_end(form, {'render_rest': false}) }}

http://symfony.com/doc/current/reference/forms/twig_reference.html

BTW, I would suggest to add your logic in your FormType.

like image 84
Christophe Willemsen Avatar answered Nov 15 '22 22:11

Christophe Willemsen


You can force the items to having been rendered like..

{% do form.filterStart.setRendered %}
{% do form.filterEnd.setRendered %}

If you are using {{ form_end(form, {'render_rest': false}) }} then you should be aware that you would need to render your CSRF token, unless you have specifically turned it off.

Both of these approaches may clear the values on your model due to them not being in the posted data.

Alternatively you can just place the fields in a hidden div, but this is a little hacky (then again the other ways are too).

The best way, as mentioned by Christophe, would be to add this into your form logic. The way you choose to do this would depend on whether the availability of these fields depends on a predetermined factor or on data coming from the actual model.

Predetermined

Your Form Type

class YourFormType extends AbstractType
{
    //...

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        //...

        if ($options['your_condition']) {
            $builder
                ->add('filterStart', 'date')
                ->add('filterEnd', 'date')
            ;
        }
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            //...
            'your_condition' => false,
        ));
    }

    //...
}

Creating Your Form

$form = $formFactory->create(
        // Or $this->createForm if you are using the controller
    'your_form_name', 
    $model, 
    array('your_condition' => true/false)
);

From The Model

Form Type

class YourFormType extends AbstractType
{
    //...

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        //...

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

                if (!$model || 'something' !== $model->getSomething()) {
                    return;
                }

                $form
                    ->add('filterStart', 'date')
                    ->add('filterEnd', 'date')
                ;
            })
        ;
    }

    //...
}

Bother of these would then require you to check that the fields had been created when rendering them in your template like..

{% if form.filterStart is defined and form.filterEnd is defiend %}
    <div class="container-filters">
        <div class="form-group">
            {{ form_row(form.filterStart) }}
        </div>
        <div class="form-group">
            {{ form_row(form.filterEnd) }}
        </div>
        <input type="submit" name="submit" class="btn btn-evo" value="OK" />
    </div>
{% endif %}
like image 10
qooplmao Avatar answered Nov 15 '22 23:11

qooplmao