Thursday, September 3, 2015

How to theme the individual fields for collection type of a form

Solution 1 - override the collection_widget theme:

Let's say we have a form looks like this:

<?php
$entity = 'MyDemoBundle:User';
$id = 5;

$user = $this->getDoctrine()->getRepository($entity)->find($id);

$formName = 'contactsform';

$formDefault = array(
  'username' => $user->getUsername(),
  'contacts' => $user->getContacts(),
);

$formAttr = array('attr' => array(
  'class' => $formName,
));

$form = $this->get('form.factory')->createNamedBuilder($formName, 'form', $formDefault, $formAttr)
    ->add('username', 'text')
    ->add('contacts', 'collection', array(
      'type' => new ContactType(),
      'allow_add' => TRUE,
      'allow_delete' => TRUE,
    ))
    ->add('save', 'submit', array('label' => 'Save'))
    ->getForm();
?>

And the ContactType looks like this:

<?php
namespace My\DemoBundle\Form\Type;

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

class ContactType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('firstname', 'text');
        $builder->add('lastname');
        $builder->add('email');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'My\DemoBundle\Entity\Contact',
        ));
    }

    public function getName()
    {
        return 'contact';
    }
}
?>

You can override the collection_widget theme for a single field by referencing the widget like this:

{# src/My/DemoBundle/Resources/views/Form/cust_field_contacts.html.twig #}

{%- block _contactsform_contacts_widget -%}
  {%- for child in form -%}
    {{- form_widget(child) -}}
  {%- endfor -%}
{%- endblock -%}

{%- block _contactsform_contacts_entry_widget -%}
  <li class="test_row">
    {%- for child in form -%}
      <div style="display: inline-block;">
        {{- form_widget(child) -}}
      </div>
    {%- endfor -%}
  </li>
{%- endblock -%}

Note: change the "contactsform" to your form name.

Note: change the "contacts" to your collection type.

Note: the "dash" between the twig tags are for triming the whitespace. For more information, please visit http://twig.sensiolabs.org/doc/templates.html#whitespace-control

To find the unique block name in order to override the built-in one:

{{ dump(form.contacts.vars.prototype) }}
or

{{ dump(child) }}

Then, look for vars > unique_block_prefix, you will see:

FormView {
  vars: array:27 [
    "unique_block_prefix" => "_contactsform_contacts_entry"
  ]
}

To theme an individual field:

{# src/My/DemoBundle/Resources/views/Form/cust_field_contacts.html.twig #}

{%- block _contactsform_contacts_entry_firstname_widget -%}
  <div class="text_widget cust_firstname">
    {{- block('form_widget_simple') -}}
  </div>
{%- endblock -%}

Note: the magic trick here is the "entry" where twig will do the job for you to apply above changes to each row and for each field you specify

Note: change the "contactsform" to your form name.

Note: change the "contacts" to your collection type.

Then, render the label, any errors, and the HTML form widget for the given "collection" widget:

{# src/My/DemoBundle/Resources/views/Contact/contact.html.twig #}

{% form_theme form 'MyDemoBundle:Form:cust_field_contacts.html.twig' %}

{%- block body -%}

  {{- form_row(form.contacts) -}}

{%- endblock -%}

Reference:
http://stackoverflow.com/questions/11498487/symfony2-applying-theme-to-individual-field-for-collection-type

No comments: