Reputation: 540
Given the simple form build:
$form = add('a')
->add('b')
->add('c')
->add('d')
->add('e')
->add('f');
I'd like to wrap a div tag around ABC and DEF, like so:
<div class="section1">
<input type="text" name="a" />
<input type="text" name="b" />
<input type="text" name="c" />
</div>
<div class="section2">
<input type="text" name="d" />
<input type="text" name="e" />
<input type="text" name="f" />
</div>
Problem is, I am just able to use the Symfony Form Component for this project. Is there a way with twig to render the form fields in groups like above? I will need to specify logic that says something simliar to "start section 1 with 'a' and section 2 with 'd'", so this way if any fields change inbetween (say we remove the field with the name 'b') the form will still work.
My twig file looks like this, which is obviously not correct:
<form action="#" method="POST" {{ form_enctype(form) }}>
{% for child in form.children %}
<div class="form_row">
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endfor %}
</form>
Upvotes: 2
Views: 4379
Reputation: 121
The best way to do it I think is building the form outside the controller (as a class, extending AbstracType)
So, you will need these files:
So, the idea is building one single form (MyFormType) made by many individual section forms (Section1Type and Section2Type). Then calling this main form in your controller and rendering it in your template (with a "for" loop for each section).
So here you have the code:
Your controller:
<?php
# /src/Acme/DefaultBundle/Controller/DefaultController.php
namespace Acme\DefaultBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\DefaultBundle\Form\MyFormType;
class DefaultController extends Controller
{
public function indexAction()
{
$form = $this->createForm(new MyFormType());
return $this->render('AcmeDefaultBundle:Default:index.html.twig', array(
'form' => $form->createView()
));
}
}
Your template:
{# /src/Acme/DefaultBundle/Resources/views/Default/index.html.twig #}
{{ form_start(form) }}
<div class="section1">
{% for input in form.section1 %}
{{ form_label(input) }}
{{ form_widget(input) }}
<br>
{% endfor %}
</div>
<div class="section2">
{% for input in form.section2 %}
{{ form_label(input) }}
{{ form_widget(input) }}
<br>
{% endfor %}
</div>
{{ form_end(form) }}
The main form:
<?php
# /src/Acme/DefaultBundle/Form/MyFormType.php
namespace Acme\DefaultBundle\Form;
use Acme\DefaultBundle\Form\Section1Type;
use Acme\DefaultBundle\Form\Section2Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class MyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// This calls your section forms as many as you need
$builder->add('section1', new Section1Type());
$builder->add('section2', new Section2Type());
$builder->add('Send', 'submit');
}
public function getName()
{
return 'myform';
}
}
The Section1 form:
<?php
# /src/Acme/DefaultBundle/Form/Section1Type.php
namespace Acme\DefaultBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class Section1Type extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('a', 'text');
$builder->add('b', 'text');
$builder->add('c', 'text');
}
public function getName()
{
return 'section1';
}
}
And Section2 form:
<?php
# /src/Acme/DefaultBundle/Form/Section2Type.php
namespace Acme\DefaultBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class Section2Type extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('d', 'text');
$builder->add('e', 'text');
$builder->add('f', 'text');
}
public function getName()
{
return 'section2';
}
}
And that's it, you can edit each individual section (adding and removing inputs) and you will get all of them in your template without modifying it.
Upvotes: 3