Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable a field in edit view using Symfony 2 FormBuilder

I created a form with Symfony2 FormBuilder and I want to disabled one of the fields in the edit view. I'm actually hiding it with a wrapper (display:none) but I was wondering if there's a better way to do this. My code looks like the following:

EntityType

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('fieldToDisabledInEditView');
    // ...

EntityController

public function newAction() {
    $entity = new Entity;
    $form = $this->createForm(new EntityType, $entity);
    // ...
}
public function editAction() {
    $entity = new Entity;
    $form = $this->createForm(new EntityType, $entity);
    // ...
}

New (twig) Template

<form>
    {{ form_row(form.fieldToDisabledInEditView) }}
    {# ... #}

Edit (twig) Template

<form>
    <span class="theValueOfTheHiddenField">{{ entity.fieldToDisabledInEditView }}</span>
    <div style="display:none">
        {{ form_row(form.fieldToDisabledInEditView) }}
    </div>
    {# ... #}
like image 573
viarnes Avatar asked Aug 16 '13 13:08

viarnes


2 Answers

I think you will find that you will have other differences between create and edit, especially validation groups. Since your controller knows which operation is being done then consider creating two form types EditEntity and CreateEntity and then using a common base to minimize duplicate code. @cheesemackfly shows how to add a disabled attribute to an element.

But of course you probably feel that having two forms is a waste for such a simple difference. In which case, add a intention flag to your class and set it in the controller

class EntityType
{
    public function __construct($intention)
    {
        $this->intention = $intention;

     ...
    // Use $this->intention to tweak the form

    }
}

// controller
$form = $this->createForm(new EntityType('create'), $entity);
OR
$form = $this->createForm(new EntityType('edit'), $entity);

If you really want to get into it then use di to inject the intention.

 // controller
 $formType = $this->get('entity.create.formtype');
 OR
 $formType = $this->get('entity.edit.formtype');

By using services you can start with just the one formtype and then when you end up splitting it into two (which you will) your controllers will still work as before.

And one more thing, you can actually set the disabled attribute directly in twig assuming you are using different templates for edit/create. So no code changes at all.

{{ form_row(form.yourField, { 'attr':{'disabled':'disabled'} }) }}

======================================================================== Update: 03 March 2016

Just in case anybody stumbles across this, be aware the Symfony 3 no longer supports having one class implement multiple form types. You basically have to have individual form type classes even if they are almost identical. And never add instance data to your form types.

like image 200
Cerad Avatar answered Sep 21 '22 05:09

Cerad


This is the typical case where you can use an event subscriber to a form class.
In your case, it should be as:

// src/Acme/DemoBundle/Form/EventListener/AddfieldToDisabledInEditViewSubscriber.php
namespace Acme\DemoBundle\Form\EventListener;

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

class AddfieldToDisabledInEditViewSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        // Tells the dispatcher that you want to listen on the form.pre_set_data
        // event and that the preSetData method should be called.
        return array(FormEvents::PRE_SET_DATA => 'preSetData');
    }

    public function preSetData(FormEvent $event)
    {
        $data = $event->getData();
        $form = $event->getForm();

        // check if the object is "new"
        // If you didn't pass any data to the form, the data is "null".
        // This should be considered a new object
        if (!$data || !$data->getId()) {
            $form->add('fieldToDisabledInEditView');
        }
        else
        {
            $form->add('fieldToDisabledInEditView', null, array('disabled' => true));
            //If PHP >= 5.4
            //$form->add('fieldToDisabledInEditView', null, ['disabled' => true]);
        }
    }
}

And in your form type:

// src/Acme/DemoBundle/Form/Type/EntityType.php
namespace Acme\DemoBundle\Form\Type;

// ...
use Acme\DemoBundle\Form\EventListener\AddfieldToDisabledInEditViewSubscriber;

class EntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('your_field');
        //...

        $builder->addEventSubscriber(new AddfieldToDisabledInEditViewSubscriber());
    }

    // ...
}

http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

like image 24
cheesemacfly Avatar answered Sep 24 '22 05:09

cheesemacfly